diff --git a/src/bcf/bcf/v3/bcfapi.py b/src/bcf/bcf/v3/bcfapi.py index 7d54ee07c5..0ec2cf262f 100644 --- a/src/bcf/bcf/v3/bcfapi.py +++ b/src/bcf/bcf/v3/bcfapi.py @@ -7,6 +7,8 @@ import webbrowser import http.server import base64 +from werkzeug.datastructures import HeaderSet + client_id, client_secret = "", "" @@ -141,42 +143,67 @@ class BcfClient: def get(self, endpoint, params=None, is_auth_required=False): # TODO: handle error http status codes and raise exception. Follow error.json standard. headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()} - return requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None).json() + response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None) + try: + response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None) + if response.status_code == 200: + return response.json() + response.raise_for_status() + except requests.exceptions.HTTPError as e: + print(f"message: {response.reason}' '{response.status_code}' '{ e }") def post(self, endpoint, data=None, params=None): headers = { "Authorization": "Bearer " + self.foundation_client.get_access_token(), "Content-type": "application/json", } - resp = requests.post( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - data=data or None, - ) - return resp.status_code, resp.text + try: + response = requests.post( + f"{self.baseurl}{endpoint}", + headers=headers, + params=params or None, + data=data or None, + ) + if response.status_code == 201: + return response.status_code, response.text + response.raise_for_status() + except requests.exceptions.HTTPError as errh: + print(f"message: {response.reason}' '{response.status_code}, {errh}") def put(self, endpoint, data=None, params=None): headers = { "Authorization": "Bearer " + self.foundation_client.get_access_token(), "Content-type": "application/json", } - resp = requests.put( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - data=data or None, - ) - return resp.status_code, resp.text + try: + response = requests.put( + f"{self.baseurl}{endpoint}", + headers=headers, + params=params or None, + data=data or None, + ) + if response.status_code == 200: + return response.status_code, response.text + response.raise_for_status() + except requests.exceptions.HTTPError as errh: + print(f"message: {response.reason}' '{response.status_code}, {errh}") def delete(self, endpoint, params=None): - headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()} - resp = requests.put( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - ) - return resp.status_code + headers = { + "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Content-type": "application/json", + } + try: + response = requests.delete( + f"{self.baseurl}{endpoint}", + headers=headers, + params=params or None, + ) + if response.status_code == 200: + return response.status_code, response.text + response.raise_for_status() + except requests.exceptions.HTTPError as errh: + print(f"message: {response.reason}' '{response.status_code}, {errh}") def get_projects(self) -> list: return self.get( @@ -246,16 +273,30 @@ class BcfClient: return self.delete(f"/projects/{project_id}/topics/{topic_id}") def get_snippet(self, project_id="", topic_id="") -> str: - return self.get( - f"/projects/{project_id}/topics/{topic_id}/snippet", - { - "project_id": project_id, - "topic_id": topic_id, - }, + headers = { + "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Content-type": "application/octet-stream", + } + response = requests.get( + f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", + headers=headers, ) + # TODO: write to tmpdir + with open(f"{project_id}_{topic_id}_snippet.txt", "w") as f: + f.write(response.content.decode("utf-8")) + return response.status_code, response.content - def update_snippet(self, project_id="", topic_id="", data=None): - return self.put(f"/projects/{project_id}/topics", data=data) + def update_snippet(self, project_id="", topic_id="", files=None, data=None): + headers = { + "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Content-type": "application/octet-stream", + } + response = requests.put( + f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", + headers=headers, + files=files, + ) + return response.status_code def get_files_information(self, project_id="") -> list: return self.get( @@ -478,6 +519,7 @@ class BcfClient: project_id="", topic_id="", guid=None, + files=None, data=None, ): headers = { @@ -488,18 +530,23 @@ class BcfClient: f"/projects/{project_id}/topics/{topic_id}/documents", data=data, params={guid}, + files=files, headers=headers, ) + return response.status_code def get_document(self, project_id="", topic_id="", document_id="") -> str: - return self.get( - f"/projects/{project_id}/topics/{topic_id}/documents/{document_id}", - { - "project_id": project_id, - "topic_id": topic_id, - "document_id": document_id, - }, + headers = { + "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Content-type": "application/octet-stream", + } + response = requests.get( + f"{self.baseurl}/projects/{project_id}/topics/documents/{document_id}", + headers=headers, ) + with open(f"{project_id}_{topic_id}_{document_id}_document.txt", "w") as f: + f.write(response.content.decode("utf-8")) + return response.status_code, response.content def get_topics_events(self, project_id="") -> list: return self.get( diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index 63ceb6ce09..39d0b78b7a 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -402,6 +402,13 @@ endif cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/ rm -rf dist/working + # Provides OpenLCA fucntionality + mkdir dist/working + cd dist/working && wget https://files.pythonhosted.org/packages/85/33/f91b96e9e8608ff65a003b692e8a9cdd60f2178f60617e5b1d21334c009c/olca-ipc-0.0.10.tar.gz + cd dist/working && tar -xzvf olca-ipc* + cd dist/working/olca-ipc-0.0.10/ && cp -r olca ../../blenderbim/libs/site/packages/ + rm -rf dist/working + cd dist/blenderbim && sed -i "s/999999/$(VERSION)/" __init__.py cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./* rm -rf dist/blenderbim diff --git a/src/blenderbim/RenameObjects.py b/src/blenderbim/RenameObjects.py deleted file mode 100644 index f3e38daafc..0000000000 --- a/src/blenderbim/RenameObjects.py +++ /dev/null @@ -1,119 +0,0 @@ -import bpy -from bpy.types import Operator - - -class Object_OT_RenameObjects(Operator): - bl_idname = "object.renameobjects" - bl_label = "Rename Object(s)" - - # Multi Object rename UI - BNameCB: bpy.props.BoolProperty(name="Base Name:") - BaseName: bpy.props.StringProperty(name="") - PreFixCB: bpy.props.BoolProperty(name="Prefix:") - PreFix: bpy.props.StringProperty(name="") - RemFrst: bpy.props.BoolProperty(name="Remove First") - DgtFrst: bpy.props.IntProperty(name="Digits") - SuffixCB: bpy.props.BoolProperty(name="Suffix") - Suffix: bpy.props.StringProperty(name="") - RemLast: bpy.props.BoolProperty(name="Remove Last") - DgtLast: bpy.props.IntProperty(name="Digits") - NumbredCB: bpy.props.BoolProperty(name="Numbred") - BaseNum: bpy.props.IntProperty(name="Base Number") - Step: bpy.props.IntProperty(name="Step", default=1) - findCB: bpy.props.BoolProperty(name="Replace") - find: bpy.props.StringProperty(name="") - replace: bpy.props.StringProperty(name="") - # Single rename UI - Name: bpy.props.StringProperty(name="Name") - - def draw(self, ctx): - SelCount = len(bpy.context.selected_objects) - if SelCount > 1: - box = self.layout.box() - row = box.row() - row.prop(self, "BNameCB") - row.prop(self, "BaseName") - row = box.row() - row.prop(self, "PreFixCB") - row.prop(self, "PreFix") - row = box.row() - row.prop(self, "RemFrst") - row.prop(self, "DgtFrst") - row = box.row() - row.prop(self, "SuffixCB") - row.prop(self, "Suffix") - row = box.row() - row.prop(self, "RemLast") - row.prop(self, "DgtLast") - row = box.row(align=True) - row.prop(self, "NumbredCB") - row.prop(self, "BaseNum") - row.prop(self, "Step") - row = box.row(align=True) - row.prop(self, "findCB") - row.prop(self, "find") - row.prop(self, "replace") - if SelCount == 1: - box = self.layout.box() - row = box.row() - row.prop(self, "Name") - if SelCount == 0: - box = self.layout.box() - row = box.row() - row.label("No Selected Object") - - def __init__(self): - if len(bpy.context.selected_objects) == 1: - self.Name = bpy.context.selected_objects[0].name - - def execute(self, context): - SelCount = len(bpy.context.selected_objects) - if SelCount > 1: - SelObj = bpy.context.selected_objects - Index = self.BaseNum - for i in range(0, SelCount): - # Get Object Original Name # - NewName = SelObj[i].name - # Set the Base name # - if self.BNameCB: - NewName = self.BaseName - # Remove First characters # - if self.RemFrst: - NewName = NewName[self.DgtFrst : self.DgtFrst + len(NewName)] - # Remove Last Characters # - if self.RemLast: - NewName = NewName[1 : len(NewName) - self.DgtLast] - # Add Prefix to the new name # - if self.PreFixCB: - NewName = self.PreFix + NewName - # Add Suffix to the new name # - if self.SuffixCB: - NewName = NewName + self.Suffix - # Add Digits to end of new name # - if self.NumbredCB: - NewName += str(Index) - Index += self.Step - # Find and Replace # - if self.findCB: - NewName = NewName.replace(self.find, self.replace) - # Set the new name to the object # - SelObj[i].name = NewName - elif SelCount == 1: - bpy.context.selected_objects[0].name = self.Name - return {"FINISHED"} - - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_props_dialog(self) - - -def register(): - bpy.utils.register_class(Object_OT_RenameObjects) - - -def unregister(): - bpy.utils.unregister_class(Object_OT_RenameObjects) - - -if __name__ == "__main__": - register() diff --git a/src/blenderbim/blenderbim/__init__.py b/src/blenderbim/blenderbim/__init__.py index 3251fdd873..1fd0f93247 100644 --- a/src/blenderbim/blenderbim/__init__.py +++ b/src/blenderbim/blenderbim/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + bl_info = { "name": "BlenderBIM", "description": "Author, import, and export files in the " "Industry Foundation Classes (.ifc) file format", diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index 92699dc4dd..5df49888d9 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + # Check if we are running in Blender before loading, to allow for multiprocessing import sys @@ -44,6 +63,7 @@ if bpy is not None: "document": None, "pset_template": None, "clash": None, + "lca": None, "csv": None, "bimtester": None, "diff": None, diff --git a/src/blenderbim/blenderbim/bim/data/styles/default.css b/src/blenderbim/blenderbim/bim/data/styles/default.css index 133c191ce1..a84543626e 100644 --- a/src/blenderbim/blenderbim/bim/data/styles/default.css +++ b/src/blenderbim/blenderbim/bim/data/styles/default.css @@ -1,3 +1,23 @@ +/* + * BlenderBIM Add-on - OpenBIM Blender Add-on + * Copyright (C) 2020, 2021 Dion Moult + * + * This file is part of BlenderBIM Add-on. + * + * BlenderBIM Add-on is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BlenderBIM Add-on is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with BlenderBIM Add-on. If not, see . + */ + * { stroke-linecap: round; stroke-linejoin: round; } *[id] { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; } .projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } diff --git a/src/blenderbim/blenderbim/bim/data/styles/sample.css b/src/blenderbim/blenderbim/bim/data/styles/sample.css index a265db20a6..c0a7b0ec74 100644 --- a/src/blenderbim/blenderbim/bim/data/styles/sample.css +++ b/src/blenderbim/blenderbim/bim/data/styles/sample.css @@ -1,3 +1,23 @@ +/* + * BlenderBIM Add-on - OpenBIM Blender Add-on + * Copyright (C) 2020, 2021 Dion Moult + * + * This file is part of BlenderBIM Add-on. + * + * BlenderBIM Add-on is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BlenderBIM Add-on is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with BlenderBIM Add-on. If not, see . + */ + .cut { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; } .background { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } .annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index 7b849b6fc3..5a2113fa08 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 447f1f9eb4..ac0d0206ca 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -1,7 +1,27 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import addon_utils import ifcopenshell.api.owner.settings +from blenderbim.bim.module.drawing.prop import RasterStyleProperty from bpy.app.handlers import persistent from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.owner.prop import getPersons, getOrganisations @@ -133,8 +153,7 @@ def purge_module_data(): def loadIfcStore(scene): IfcStore.purge() purge_module_data() - ifc_file = IfcStore.get_file() - if not ifc_file: + if not IfcStore.get_file(): return IfcStore.get_schema() IfcStore.reload_linked_elements() @@ -212,12 +231,12 @@ def setDefaultProperties(scene): ) ifcopenshell.api.owner.settings.get_person = ( lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person)) - if getPersons(None, bpy.context) and bpy.context.scene.BIMOwnerProperties.user_person + if getPersons(None, None) and bpy.context.scene.BIMOwnerProperties.user_person else None ) ifcopenshell.api.owner.settings.get_organisation = ( lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation)) - if getOrganisations(None, bpy.context) and bpy.context.scene.BIMOwnerProperties.user_organisation + if getOrganisations(None, None) and bpy.context.scene.BIMOwnerProperties.user_organisation else None ) ifcopenshell.api.owner.settings.get_application = get_application @@ -227,30 +246,30 @@ def setDefaultProperties(scene): drawing_style.render_type = "VIEWPORT" drawing_style.raster_style = json.dumps( { - "bpy.data.worlds[0].color": (1, 1, 1), - "bpy.context.scene.render.engine": "BLENDER_WORKBENCH", - "bpy.context.scene.render.film_transparent": False, - "bpy.context.scene.display.shading.show_object_outline": True, - "bpy.context.scene.display.shading.show_cavity": False, - "bpy.context.scene.display.shading.cavity_type": "BOTH", - "bpy.context.scene.display.shading.curvature_ridge_factor": 1, - "bpy.context.scene.display.shading.curvature_valley_factor": 1, - "bpy.context.scene.view_settings.view_transform": "Standard", - "bpy.context.scene.display.shading.light": "FLAT", - "bpy.context.scene.display.shading.color_type": "SINGLE", - "bpy.context.scene.display.shading.single_color": (1, 1, 1), - "bpy.context.scene.display.shading.show_shadows": False, - "bpy.context.scene.display.shading.shadow_intensity": 0.5, - "bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5), - "bpy.context.scene.view_settings.use_curve_mapping": False, - "space.overlay.show_wireframes": True, - "space.overlay.wireframe_threshold": 0, - "space.overlay.show_floor": False, - "space.overlay.show_axis_x": False, - "space.overlay.show_axis_y": False, - "space.overlay.show_axis_z": False, - "space.overlay.show_object_origins": False, - "space.overlay.show_relationship_lines": False, + RasterStyleProperty.WORLD_COLOR.value: (1, 1, 1), + RasterStyleProperty.RENDER_ENGINE.value: "BLENDER_WORKBENCH", + RasterStyleProperty.RENDER_TRANSPARENT.value: False, + RasterStyleProperty.SHADING_SHOW_OBJECT_OUTLINE.value: True, + RasterStyleProperty.SHADING_SHOW_CAVITY.value: False, + RasterStyleProperty.SHADING_CAVITY_TYPE.value: "BOTH", + RasterStyleProperty.SHADING_CURVATURE_RIDGE_FACTOR.value: 1, + RasterStyleProperty.SHADING_CURVATURE_VALLEY_FACTOR.value: 1, + RasterStyleProperty.VIEW_TRANSFORM.value: "Standard", + RasterStyleProperty.SHADING_LIGHT.value: "FLAT", + RasterStyleProperty.SHADING_COLOR_TYPE.value: "SINGLE", + RasterStyleProperty.SHADING_SINGLE_COLOR.value: (1, 1, 1), + RasterStyleProperty.SHADING_SHOW_SHADOWS.value: False, + RasterStyleProperty.SHADING_SHADOW_INTENSITY.value: 0.5, + RasterStyleProperty.DISPLAY_LIGHT_DIRECTION.value: (0.5, 0.5, 0.5), + RasterStyleProperty.VIEW_USE_CURVE_MAPPING.value: False, + RasterStyleProperty.OVERLAY_SHOW_WIREFRAMES.value: True, + RasterStyleProperty.OVERLAY_WIREFRAME_THRESHOLD.value: 0, + RasterStyleProperty.OVERLAY_SHOW_FLOOR.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_X.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_Y.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_Z.value: False, + RasterStyleProperty.OVERLAY_SHOW_OBJECT_ORIGINS.value: False, + RasterStyleProperty.OVERLAY_SHOW_RELATIONSHIP_LINES.value: False, } ) drawing_style = bpy.context.scene.DocProperties.drawing_styles.add() @@ -258,30 +277,30 @@ def setDefaultProperties(scene): drawing_style.render_type = "VIEWPORT" drawing_style.raster_style = json.dumps( { - "bpy.data.worlds[0].color": (1, 1, 1), - "bpy.context.scene.render.engine": "BLENDER_WORKBENCH", - "bpy.context.scene.render.film_transparent": False, - "bpy.context.scene.display.shading.show_object_outline": True, - "bpy.context.scene.display.shading.show_cavity": True, - "bpy.context.scene.display.shading.cavity_type": "BOTH", - "bpy.context.scene.display.shading.curvature_ridge_factor": 1, - "bpy.context.scene.display.shading.curvature_valley_factor": 1, - "bpy.context.scene.view_settings.view_transform": "Standard", - "bpy.context.scene.display.shading.light": "STUDIO", - "bpy.context.scene.display.shading.color_type": "MATERIAL", - "bpy.context.scene.display.shading.single_color": (1, 1, 1), - "bpy.context.scene.display.shading.show_shadows": True, - "bpy.context.scene.display.shading.shadow_intensity": 0.5, - "bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5), - "bpy.context.scene.view_settings.use_curve_mapping": False, - "space.overlay.show_wireframes": True, - "space.overlay.wireframe_threshold": 0, - "space.overlay.show_floor": False, - "space.overlay.show_axis_x": False, - "space.overlay.show_axis_y": False, - "space.overlay.show_axis_z": False, - "space.overlay.show_object_origins": False, - "space.overlay.show_relationship_lines": False, + RasterStyleProperty.WORLD_COLOR.value: (1, 1, 1), + RasterStyleProperty.RENDER_ENGINE.value: "BLENDER_WORKBENCH", + RasterStyleProperty.RENDER_TRANSPARENT.value: False, + RasterStyleProperty.SHADING_SHOW_OBJECT_OUTLINE.value: True, + RasterStyleProperty.SHADING_SHOW_CAVITY.value: True, + RasterStyleProperty.SHADING_CAVITY_TYPE.value: "BOTH", + RasterStyleProperty.SHADING_CURVATURE_RIDGE_FACTOR.value: 1, + RasterStyleProperty.SHADING_CURVATURE_VALLEY_FACTOR.value: 1, + RasterStyleProperty.VIEW_TRANSFORM.value: "Standard", + RasterStyleProperty.SHADING_LIGHT.value: "STUDIO", + RasterStyleProperty.SHADING_COLOR_TYPE.value: "MATERIAL", + RasterStyleProperty.SHADING_SINGLE_COLOR.value: (1, 1, 1), + RasterStyleProperty.SHADING_SHOW_SHADOWS.value: True, + RasterStyleProperty.SHADING_SHADOW_INTENSITY.value: 0.5, + RasterStyleProperty.DISPLAY_LIGHT_DIRECTION.value: (0.5, 0.5, 0.5), + RasterStyleProperty.VIEW_USE_CURVE_MAPPING.value: False, + RasterStyleProperty.OVERLAY_SHOW_WIREFRAMES.value: True, + RasterStyleProperty.OVERLAY_WIREFRAME_THRESHOLD.value: 0, + RasterStyleProperty.OVERLAY_SHOW_FLOOR.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_X.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_Y.value: False, + RasterStyleProperty.OVERLAY_SHOW_AXIS_Z.value: False, + RasterStyleProperty.OVERLAY_SHOW_OBJECT_ORIGINS.value: False, + RasterStyleProperty.OVERLAY_SHOW_RELATIONSHIP_LINES.value: False, } ) drawing_style = bpy.context.scene.DocProperties.drawing_styles.add() diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index fefb377c45..8b7dfc6c1d 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import math @@ -11,33 +30,30 @@ from blenderbim.bim.ifc import IfcStore def draw_attributes(props, layout, copy_operator=None): for attribute in props: row = layout.row(align=True) - value = None - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - value = attribute.string_value - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - value = attribute.bool_value - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - value = attribute.int_value - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - value = attribute.float_value - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - value = attribute.enum_value - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") - if copy_operator: - op = row.operator(f"{copy_operator}", text="", icon="COPYDOWN") - op.data = json.dumps({"name": attribute.name, "value": value, "is_null": attribute.is_null}) + draw_attribute(attribute, row, copy_operator) + + +def draw_attribute(attribute, layout, copy_operator=None): + value_name = attribute.get_value_name() + if not value_name: + layout.label(text=attribute.name) + return + layout.prop( + attribute, + value_name, + text=attribute.name, + ) + if attribute.is_optional: + layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + if copy_operator: + op = layout.operator(f"{copy_operator}", text="", icon="COPYDOWN") + op.data = json.dumps({"name": attribute.name, "value": attribute.get_value(), "is_null": attribute.is_null}) def import_attributes(ifc_class, props, data, callback=None): for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes(): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or (isinstance(data_type, tuple) and "entity" in ".".join(data_type)): + if isinstance(data_type, tuple) or data_type == "entity": callback(attribute.name(), None, data) if callback else None continue new = props.add() @@ -69,18 +85,6 @@ def export_attributes(props, callback=None): for prop in props: is_handled_by_callback = callback(attributes, prop) if callback else False if is_handled_by_callback: - continue # Our job is done - - if prop.is_null: - attributes[prop.name] = None - elif prop.data_type == "string": - attributes[prop.name] = prop.string_value - elif prop.data_type == "boolean": - attributes[prop.name] = prop.bool_value - elif prop.data_type == "integer": - attributes[prop.name] = prop.int_value - elif prop.data_type == "float": - attributes[prop.name] = prop.float_value - elif prop.data_type == "enum": - attributes[prop.name] = prop.enum_value + continue # Our job is done + attributes[prop.name] = prop.get_value() return attributes diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index c83dc0e613..e779befc27 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import uuid import ifcopenshell @@ -41,11 +60,26 @@ class IfcStore: IfcStore.path = bpy.context.scene.BIMProperties.ifc_file if IfcStore.path: try: - IfcStore.file = ifcopenshell.open(IfcStore.path) + IfcStore.load_file(IfcStore.path) except: - IfcStore.file + pass return IfcStore.file + @staticmethod + def load_file(path): + extension = path.split(".")[-1] + if extension.lower() == "ifczip": + with tempfile.TemporaryDirectory() as unzipped_path: + with zipfile.ZipFile(path, "r") as zip_ref: + zip_ref.extractall(unzipped_path) + for filename in Path(unzipped_path).glob("**/*.ifc"): + IfcStore.file = ifcopenshell.open(filename) + return + elif extension.lower() == "ifcxml": + IfcStore.file = ifcopenshell.file(ifcopenshell.ifcopenshell_wrapper.parse_ifcxml(path)) + elif extension.lower() == "ifc": + IfcStore.file = ifcopenshell.open(path) + @staticmethod def get_schema(): if IfcStore.file is None: diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index bd32c16cfd..0b174f0c77 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import ifcopenshell import ifcopenshell.geom import ifcopenshell.util.geolocation @@ -195,8 +214,6 @@ class IfcImporter: self.profile_code("Purge diffs") self.load_file() self.profile_code("Loading file") - self.set_ifc_file() - self.profile_code("Setting file") self.calculate_unit_scale() self.profile_code("Calculate unit scale") self.calculate_model_offset() @@ -207,6 +224,8 @@ class IfcImporter: self.profile_code("Create project") self.create_spatial_hierarchy() self.profile_code("Create spatial hierarchy") + self.process_element_filter() + self.profile_code("Process element filter") self.create_aggregates() self.profile_code("Create aggregates") self.create_aggregate_tree() @@ -217,8 +236,6 @@ class IfcImporter: self.profile_code("Create materials") self.create_styles() self.profile_code("Create styles") - self.process_element_filter() - self.profile_code("Process element filter") self.parse_native_elements() self.profile_code("Parsing native elements") self.create_grids() @@ -273,16 +290,20 @@ class IfcImporter: return abs(coords[0]) > limit or abs(coords[1]) > limit or abs(coords[2]) > limit def process_element_filter(self): - if not self.ifc_import_settings.ifc_selector: + if self.ifc_import_settings.ifc_import_filter == "NONE" or not self.ifc_import_settings.ifc_selector: + self.elements = self.file.by_type("IfcElement") return + selector = ifcopenshell.util.selector.Selector() elements = selector.parse(self.file, self.ifc_import_settings.ifc_selector) if self.ifc_import_settings.ifc_import_filter == "WHITELIST": self.filter_mode = "WHITELIST" self.include_elements = set(elements) + self.elements = self.include_elements elif self.ifc_import_settings.ifc_import_filter == "BLACKLIST": - self.exclude_elements = set(elements) self.filter_mode = "BLACKLIST" + self.exclude_elements = set(elements) + self.elements = [e for e in self.file.by_type("IfcElement") if e not in self.exclude_elements] def parse_native_elements(self): if self.filter_mode == "WHITELIST": @@ -620,16 +641,9 @@ class IfcImporter: def create_empty_and_2d_elements(self): curve_products = [] - if self.filter_mode == "WHITELIST": - self.elements = self.include_elements - elif self.filter_mode == "BLACKLIST": - self.elements = [e for e in self.file.by_type("IfcElement") if e not in self.exclude_elements] - else: - self.elements = self.file.by_type("IfcElement") - - for element in self.elements: - if element.id() in self.added_data: - continue + unadded_element_ids = set([e.id() for e in self.elements]) - set(self.added_data.keys()) + for element_id in unadded_element_ids: + element = self.file.by_id(element_id) if element.is_a("IfcPort"): continue if not element.Representation: @@ -954,25 +968,8 @@ class IfcImporter: def load_file(self): self.ifc_import_settings.logger.info("loading file %s", self.ifc_import_settings.input_file) - extension = self.ifc_import_settings.input_file.split(".")[-1] - if extension.lower() == "ifczip": - with tempfile.TemporaryDirectory() as unzipped_path: - with zipfile.ZipFile(self.ifc_import_settings.input_file, "r") as zip_ref: - zip_ref.extractall(unzipped_path) - for filename in Path(unzipped_path).glob("**/*.ifc"): - self.file = ifcopenshell.open(filename) - break - elif extension.lower() == "ifcxml": - self.file = ifcopenshell.file( - ifcopenshell.ifcopenshell_wrapper.parse_ifcxml(self.ifc_import_settings.input_file) - ) - elif extension.lower() == "ifc": - self.file = ifcopenshell.open(self.ifc_import_settings.input_file) - IfcStore.file = self.file - - def set_ifc_file(self): bpy.context.scene.BIMProperties.ifc_file = self.ifc_import_settings.input_file - IfcStore.path = self.ifc_import_settings.input_file + self.file = IfcStore.get_file() def calculate_unit_scale(self): self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) @@ -1038,9 +1035,17 @@ class IfcImporter: self.add_related_objects(collection, rel_aggregate.RelatedObjects) def create_aggregates(self): - rel_aggregates = [a for a in self.file.by_type("IfcRelAggregates") if a.RelatingObject.is_a("IfcElement")] - for rel_aggregate in rel_aggregates: - self.create_aggregate(rel_aggregate) + if self.filter_mode in ["WHITELIST", "BLACKLIST"]: + rel_aggregates = [e.IsDecomposedBy[0].RelatingObject for e in self.elements if e.IsDecomposedBy] + else: + rel_aggregates = [a for a in self.file.by_type("IfcRelAggregates") if a.RelatingObject.is_a("IfcElement")] + if len(rel_aggregates) > 10000: + # More than 10,000 collections makes Blender unhappy + print("Falling back to SPATIAL_DECOMPOSITION collection mode") + self.ifc_import_settings.collection_mode = "SPATIAL_DECOMPOSITION" + else: + for rel_aggregate in rel_aggregates: + self.create_aggregate(rel_aggregate) def create_aggregate_tree(self): for aggregate in self.aggregates.values(): @@ -1191,8 +1196,15 @@ class IfcImporter: ): bpy.data.objects.remove(self.spatial_structure_elements[global_id]["blender_obj"]) collection = self.spatial_structure_elements[global_id]["blender"] + elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION": + # TODO: refactor this to a more holistic collection mode feature + return self.place_object_in_spatial_tree(element.Decomposes[0].RelatingObject, obj) else: - collection = self.aggregates[element.Decomposes[0].RelatingObject.GlobalId]["blender"] + aggregate = element.Decomposes[0].RelatingObject + aggregate_data = self.aggregates.get(aggregate.GlobalId) + if not aggregate_data: + return self.place_object_in_spatial_tree(aggregate, obj) + collection = aggregate_data["blender"] if collection: collection.objects.link(obj) else: @@ -1472,6 +1484,7 @@ class IfcImportSettings: self.model_offset_coordinates = (0, 0, 0) self.ifc_import_filter = "NONE" self.ifc_selector = "" + self.collection_mode = "DECOMPOSITION" @staticmethod def factory(context, input_file, logger): diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py b/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py index d70cecd453..a97637b771 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, operator diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py index b6f49c1568..d5b972791a 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py index d136bc9afc..7f9c033b12 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from ifcopenshell.api.aggregate.data import Data from blenderbim.bim.ifc import IfcStore @@ -38,7 +57,7 @@ class BIM_PT_aggregate(Panel): row.prop(props, "relating_object", text="") if props.relating_object: row.operator("bim.assign_object", icon="CHECKMARK", text="").relating_object = props.relating_object.name - row.operator("bim.disable_editing_aggregate", icon="X", text="") + row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="") else: row = self.layout.row(align=True) name = "{}/{}".format( diff --git a/src/blenderbim/blenderbim/bim/module/attribute/__init__.py b/src/blenderbim/blenderbim/bim/module/attribute/__init__.py index f7c565111c..afa3ad0e18 100644 --- a/src/blenderbim/blenderbim/bim/module/attribute/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/attribute/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/attribute/operator.py b/src/blenderbim/blenderbim/bim/module/attribute/operator.py index 673c0ced6f..ef5798a5d9 100644 --- a/src/blenderbim/blenderbim/bim/module/attribute/operator.py +++ b/src/blenderbim/blenderbim/bim/module/attribute/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell @@ -21,8 +40,7 @@ class EnableEditingAttributes(bpy.types.Operator): obj = bpy.data.materials.get(self.obj) oprops = obj.BIMObjectProperties props = obj.BIMAttributeProperties - while len(props.attributes) > 0: - props.attributes.remove(0) + props.attributes.clear() for attribute in Data.products[oprops.ifc_definition_id]: new = props.attributes.add() if attribute["type"] == "entity" or (attribute["type"] == "list" and attribute["list_type"] == "entity"): diff --git a/src/blenderbim/blenderbim/bim/module/attribute/prop.py b/src/blenderbim/blenderbim/bim/module/attribute/prop.py index 28701a4600..d402546092 100644 --- a/src/blenderbim/blenderbim/bim/module/attribute/prop.py +++ b/src/blenderbim/blenderbim/bim/module/attribute/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.ifc import IfcStore from blenderbim.bim.prop import StrProperty, Attribute diff --git a/src/blenderbim/blenderbim/bim/module/attribute/ui.py b/src/blenderbim/blenderbim/bim/module/attribute/ui.py index 243b25353f..5bdb184576 100644 --- a/src/blenderbim/blenderbim/bim/module/attribute/ui.py +++ b/src/blenderbim/blenderbim/bim/module/attribute/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.attribute.data import Data @@ -91,6 +110,8 @@ class BIM_PT_material_attributes(Panel): @classmethod def poll(cls, context): + if not IfcStore.get_file(): + return False try: return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id) except: diff --git a/src/blenderbim/blenderbim/bim/module/augin/__init__.py b/src/blenderbim/blenderbim/bim/module/augin/__init__.py index 9bfda2e096..9f659c7088 100644 --- a/src/blenderbim/blenderbim/bim/module/augin/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/augin/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/augin/operator.py b/src/blenderbim/blenderbim/bim/module/augin/operator.py index f7b92fbab1..d4b5b0d316 100644 --- a/src/blenderbim/blenderbim/bim/module/augin/operator.py +++ b/src/blenderbim/blenderbim/bim/module/augin/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json diff --git a/src/blenderbim/blenderbim/bim/module/augin/prop.py b/src/blenderbim/blenderbim/bim/module/augin/prop.py index 35087503dc..d111ab0263 100644 --- a/src/blenderbim/blenderbim/bim/module/augin/prop.py +++ b/src/blenderbim/blenderbim/bim/module/augin/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy.props import bpy.types diff --git a/src/blenderbim/blenderbim/bim/module/augin/ui.py b/src/blenderbim/blenderbim/bim/module/augin/ui.py index 6199ba55b3..30f593846b 100644 --- a/src/blenderbim/blenderbim/bim/module/augin/ui.py +++ b/src/blenderbim/blenderbim/bim/module/augin/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy.types diff --git a/src/blenderbim/blenderbim/bim/module/bcf/__init__.py b/src/blenderbim/blenderbim/bim/module/bcf/__init__.py index ab9af36d50..c64a01ba66 100644 --- a/src/blenderbim/blenderbim/bim/module/bcf/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/bcf/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator @@ -20,6 +39,7 @@ classes = ( operator.AddBcfLabel, operator.AddBcfRelatedTopic, operator.ViewBcfTopic, + operator.RemoveBcfTopic, operator.RemoveBcfComment, operator.RemoveBcfBimSnippet, operator.RemoveBcfReferenceLink, diff --git a/src/blenderbim/blenderbim/bim/module/bcf/bcfstore.py b/src/blenderbim/blenderbim/bim/module/bcf/bcfstore.py index 853b0c928b..88ec005b3e 100644 --- a/src/blenderbim/blenderbim/bim/module/bcf/bcfstore.py +++ b/src/blenderbim/blenderbim/bim/module/bcf/bcfstore.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bcf import bcf.v2.bcfxml diff --git a/src/blenderbim/blenderbim/bim/module/bcf/operator.py b/src/blenderbim/blenderbim/bim/module/bcf/operator.py index 1477d06616..08276a0a33 100644 --- a/src/blenderbim/blenderbim/bim/module/bcf/operator.py +++ b/src/blenderbim/blenderbim/bim/module/bcf/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import bcf @@ -7,6 +26,7 @@ import numpy as np import ifcopenshell import ifcopenshell.util.unit from . import bcfstore +import blenderbim.bim.module.bcf.prop as bcf_prop from blenderbim.bim.ifc import IfcStore from math import radians, degrees, atan, tan, cos, sin from mathutils import Vector, Matrix, Euler, geometry @@ -56,13 +76,10 @@ class LoadBcfTopics(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() bcfxml.get_topics() - while len(context.scene.BCFProperties.topics) > 0: - context.scene.BCFProperties.topics.remove(0) - index = 0 - for topic_guid in bcfxml.topics.keys(): + context.scene.BCFProperties.topics.clear() + for index, topic_guid in enumerate(bcfxml.topics.keys()): new = context.scene.BCFProperties.topics.add() bpy.ops.bim.load_bcf_topic(topic_guid = topic_guid, topic_index = index) - index += 1 return {"FINISHED"} @@ -95,16 +112,17 @@ class LoadBcfTopic(bpy.types.Operator): 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) + + new.reference_links.clear() 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) + new_reference_link = new.reference_links.add() + new_reference_link.name = reference_link + + new.labels.clear() for label in topic.labels: - new2 = new.labels.add() - new2.name = label + new_label = new.labels.add() + new_label.name = label + if topic.bim_snippet: data_map = { "type": topic.bim_snippet.snippet_type, @@ -115,10 +133,10 @@ class LoadBcfTopic(bpy.types.Operator): 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) + + new.document_references.clear() for doc in topic.document_references: - new2 = new.document_references.add() + new_document_references = new.document_references.add() data_map = { "reference": doc.referenced_document, "description": doc.description, @@ -127,12 +145,13 @@ class LoadBcfTopic(bpy.types.Operator): } 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) + setattr(new_document_references, key, value) + + new.related_topics.clear() for related_topic in topic.related_topics: - new2 = new.related_topics.add() - new2.name = related_topic.guid + new_related_topic = new.related_topics.add() + new_related_topic.name = related_topic.guid + bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) return {"FINISHED"} @@ -147,8 +166,7 @@ class LoadBcfComments(bpy.types.Operator): bcfxml = bcfstore.BcfStore.get_bcfxml() bcfxml.get_comments(self.topic_guid) blender_topic = context.scene.BCFProperties.topics.get(self.topic_guid) - while len(blender_topic.comments) > 0: - blender_topic.comments.remove(0) + blender_topic.comments.clear() for comment in bcfxml.topics[self.topic_guid].comments.values(): new = blender_topic.comments.add() data_map = { @@ -196,7 +214,7 @@ class EditBcfTopicName(bpy.types.Operator): def execute(self, context): props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic bcfxml = bcfstore.BcfStore.get_bcfxml() topic = bcfxml.topics[blender_topic.name] topic.title = blender_topic.title @@ -211,7 +229,7 @@ class EditBcfTopic(bpy.types.Operator): def execute(self, context): props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic bcfxml = bcfstore.BcfStore.get_bcfxml() topic = bcfxml.topics[blender_topic.name] @@ -225,7 +243,7 @@ class EditBcfTopic(bpy.types.Operator): topic.topic_type = blender_topic.type or None bcfxml.edit_topic(topic) - props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic + props.refresh_topic(context) return {"FINISHED"} @@ -234,6 +252,7 @@ class SaveBcfProject(bpy.types.Operator): bl_label = "Save BCF Project" bl_options = {"REGISTER", "UNDO"} filepath: bpy.props.StringProperty(subtype="FILE_PATH") + filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"}) def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() @@ -250,11 +269,13 @@ class AddBcfTopic(bpy.types.Operator): bl_label = "Add BCF Topic" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.author + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() bcfxml.add_topic() - new = context.scene.BCFProperties.topics.add() - new.name = "New Topic" bpy.ops.bim.load_bcf_topics() return {"FINISHED"} @@ -264,17 +285,28 @@ class AddBcfBimSnippet(bpy.types.Operator): bl_label = "Add BCF BIM Snippet" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return all((getattr(context.scene.BCFProperties, attr, False) for attr in ( + "bim_snippet_reference", + "bim_snippet_schema", + "bim_snippet_type" + ))) + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] bim_snippet = bcf.v2.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 + bim_snippet.reference = props.bim_snippet_reference + bim_snippet.reference_schema = props.bim_snippet_schema + bim_snippet.snippet_type = props.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) + bim_snippet.reference = "" + bim_snippet.reference_schema = "" + bim_snippet.snippet_type = "" return {"FINISHED"} @@ -283,22 +315,40 @@ class AddBcfRelatedTopic(bpy.types.Operator): bl_label = "Add BCF Related Topic" bl_options = {"REGISTER", "UNDO"} - def execute(self, context): + @classmethod + def poll(cls, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic + if not props.related_topic: + return False + if props.related_topic == blender_topic.title: + # Prevent adding self as related topic + return False related_topic = None for topic in bcfxml.topics.values(): - if topic.title == blender_topic.related_topic: + if topic.title == props.related_topic: related_topic = bcf.v2.data.RelatedTopic() related_topic.guid = topic.guid break if not related_topic: - return {"FINISHED"} + return False + if str(related_topic.guid) in [t.name for t in blender_topic.related_topics]: + # Prevent adding the same related topic more than once + return False + return True + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = context.scene.BCFProperties + blender_topic = props.active_topic + related_topic = bcf.v2.data.RelatedTopic() + related_topic.guid = next((t for t in bcfxml.topics.values() if t.title == props.related_topic)).guid 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) + props.related_topic = "" return {"FINISHED"} @@ -307,21 +357,25 @@ class AddBcfHeaderFile(bpy.types.Operator): bl_label = "Add BCF Header File" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.file_reference + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] header_file = bcf.v2.data.HeaderFile() - header_file.reference = blender_topic.file_reference + header_file.reference = props.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 + if len(props.file_ifc_project) == 22: + header_file.ifc_project = props.file_ifc_project + if len(props.file_ifc_spatial_structure_element) == 22: + header_file.ifc_spatial_structure_element = props.file_ifc_spatial_structure_element bcfxml.add_file(topic, header_file) - props.active_topic_index = props.active_topic_index # refreshes the BCF Topic + props.refresh_topic(context) return {"FINISHED"} @@ -333,8 +387,9 @@ class ViewBcfTopic(bpy.types.Operator): def execute(self, context): for index, topic in enumerate(context.scene.BCFProperties.topics): - if topic.guid.lower() == self.topic_guid.lower(): + if topic.name.lower() == self.topic_guid.lower(): context.scene.BCFProperties.active_topic_index = index + break return {"FINISHED"} @@ -343,46 +398,50 @@ class AddBcfViewpoint(bpy.types.Operator): bl_label = "Add BCF Viewpoint" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.camera + def execute(self, context): - if not context.scene.camera: - return {"FINISHED"} bcfxml = bcfstore.BcfStore.get_bcfxml() + blender_camera = context.scene.camera props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] viewpoint = bcf.v2.data.Viewpoint() - if context.scene.camera.data.type == "ORTHO": + if blender_camera.data.type == "ORTHO": camera = bcf.v2.data.OrthogonalCamera() - camera.view_to_world_scale = context.scene.camera.data.ortho_scale + camera.view_to_world_scale = blender_camera.data.ortho_scale viewpoint.orthogonal_camera = camera - elif context.scene.camera.data.type == "PERSP": + elif blender_camera.data.type == "PERSP": camera = bcf.v2.data.PerspectiveCamera() - camera.field_of_view = degrees(context.scene.camera.data.angle) + camera.field_of_view = degrees(blender_camera.data.angle) viewpoint.perspective_camera = camera - camera.camera_view_point.x = context.scene.camera.location.x - camera.camera_view_point.y = context.scene.camera.location.y - camera.camera_view_point.z = context.scene.camera.location.z - direction = context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0)) + camera.camera_view_point.x = blender_camera.location.x + camera.camera_view_point.y = blender_camera.location.y + camera.camera_view_point.z = blender_camera.location.z + direction = blender_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 = context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0)) + up = blender_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 = context.scene.render.image_settings.file_format - context.scene.render.image_settings.file_format = "PNG" - old_filepath = context.scene.render.filepath - context.scene.render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png") + blender_render = context.scene.render + old_file_format = blender_render.image_settings.file_format + blender_render.image_settings.file_format = "PNG" + old_filepath = blender_render.filepath + blender_render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png") bpy.ops.render.opengl(write_still=True) - viewpoint.snapshot = context.scene.render.filepath + viewpoint.snapshot = blender_render.filepath bcfxml.add_viewpoint(topic, viewpoint) - context.scene.render.filepath = old_filepath - context.scene.render.image_settings.file_format = old_file_format - props.active_topic_index = props.active_topic_index # refreshes the BCF Topic + blender_render.filepath = old_filepath + blender_render.image_settings.file_format = old_file_format + props.refresh_topic(context) return {"FINISHED"} @@ -391,14 +450,18 @@ class RemoveBcfViewpoint(bpy.types.Operator): bl_label = "Remove BCF Viewpoint" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return bcf_prop.getBcfViewpoints(None, context) + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic 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 + props.refresh_topic(context) return {"FINISHED"} @@ -411,10 +474,29 @@ class RemoveBcfFile(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] bcfxml.delete_file(topic, self.index) - props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic + props.refresh_topic(context) + return {"FINISHED"} + + +class RemoveBcfTopic(bpy.types.Operator): + bl_idname = "bim.remove_bcf_topic" + bl_label = "Remove BCF Topic" + bl_options = {"REGISTER", "UNDO"} + guid: bpy.props.StringProperty() + + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.topics + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = context.scene.BCFProperties + topic_to_delete = props.active_topic + bcfxml.delete_topic(topic_to_delete.name) + bpy.ops.bim.load_bcf_topics() return {"FINISHED"} @@ -423,17 +505,19 @@ class AddBcfReferenceLink(bpy.types.Operator): bl_label = "Add BCF Reference Link" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.reference_link + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] - if not blender_topic.reference_link: - return {"FINISHED"} - topic.reference_links.append(blender_topic.reference_link) + topic.reference_links.append(props.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 = "" + props.reference_link = "" return {"FINISHED"} @@ -442,20 +526,22 @@ class AddBcfDocumentReference(bpy.types.Operator): bl_label = "Add BCF Document Reference" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.document_reference + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] - if not blender_topic.document_reference: - return {"FINISHED"} document_reference = bcf.v2.data.DocumentReference() - document_reference.referenced_document = blender_topic.document_reference - document_reference.description = blender_topic.document_reference_description or None + document_reference.referenced_document = props.document_reference + document_reference.description = props.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 = "" + props.document_reference = "" + props.document_reference_description = "" return {"FINISHED"} @@ -464,18 +550,20 @@ class AddBcfLabel(bpy.types.Operator): bl_label = "Add BCF Label" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BCFProperties.label + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic 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) + new.name = props.label + topic.labels.append(props.label) bcfxml.edit_topic(topic) - blender_topic.label = "" + props.label = "" return {"FINISHED"} @@ -487,7 +575,7 @@ class EditBcfReferenceLinks(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] for index, reference_link in enumerate(topic.reference_links): if reference_link == blender_topic.reference_links[index].name: @@ -505,9 +593,11 @@ class EditBcfLabels(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] for index, label in enumerate(blender_topic.labels): + if index >= len(topic.labels): + break if label.name == topic.labels[index]: continue topic.labels[index] = blender_topic.labels[index].name @@ -524,7 +614,7 @@ class RemoveBcfReferenceLink(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] del topic.reference_links[self.index] bcfxml.edit_topic(topic) @@ -541,7 +631,7 @@ class RemoveBcfLabel(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] del topic.labels[self.index] bcfxml.edit_topic(topic) @@ -557,7 +647,7 @@ class RemoveBcfBimSnippet(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] bcfxml.delete_bim_snippet(topic) blender_topic.bim_snippet.schema = "" @@ -575,7 +665,7 @@ class RemoveBcfDocumentReference(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic 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) @@ -591,7 +681,7 @@ class RemoveBcfRelatedTopic(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] del topic.related_topics[self.index] bcfxml.edit_topic(topic) @@ -608,7 +698,7 @@ class RemoveBcfComment(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] bcfxml.delete_comment(self.comment_guid, topic) bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) @@ -624,7 +714,7 @@ class EditBcfComment(bpy.types.Operator): def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic blender_comment = blender_topic.comments.get(self.comment_guid) topic = bcfxml.topics[blender_topic.name] comment = topic.comments[self.comment_guid] @@ -640,20 +730,29 @@ class AddBcfComment(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} comment_guid: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + props = context.scene.BCFProperties + if not props.comment: + return False + if props.has_related_viewpoint and not bcf_prop.getBcfViewpoints(None, context): + return False + return True + def execute(self, context): bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] - if not blender_topic.comment: - return {"FINISHED"} comment = bcf.v2.data.Comment() - comment.comment = blender_topic.comment - if blender_topic.has_related_viewpoint and blender_topic.viewpoints: + comment.comment = props.comment + if props.has_related_viewpoint: comment.viewpoint = bcf.v2.data.Viewpoint() comment.viewpoint.guid = blender_topic.viewpoints bcfxml.add_comment(topic, comment) bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) + props.comment = "" + props.has_related_viewpoint = False return {"FINISHED"} @@ -662,14 +761,20 @@ class ActivateBcfViewpoint(bpy.types.Operator): bl_label = "Activate BCF Viewpoint" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = context.scene.BCFProperties + blender_topic = props.active_topic + topic = bcfxml.topics[blender_topic.name] + return topic.viewpoints + def execute(self, context): self.file = IfcStore.get_file() bcfxml = bcfstore.BcfStore.get_bcfxml() props = context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] + blender_topic = props.active_topic topic = bcfxml.topics[blender_topic.name] - if not topic.viewpoints: - return {"FINISHED"} viewpoint_guid = blender_topic.viewpoints viewpoint = topic.viewpoints[viewpoint_guid] @@ -682,11 +787,10 @@ class ActivateBcfViewpoint(bpy.types.Operator): cam_width = context.scene.render.resolution_x cam_height = 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]) + obj.data.background_images.clear() background = obj.data.background_images.new() background.image = bpy.data.images.load( os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot) @@ -704,7 +808,7 @@ class ActivateBcfViewpoint(bpy.types.Operator): area.spaces[0].region_3d.view_perspective = "CAMERA" if self.file: - self.set_viewpoint_components(viewpoint) + self.set_viewpoint_components(viewpoint, context) gp = bpy.data.grease_pencils.get("BCF") if gp: @@ -720,10 +824,10 @@ class ActivateBcfViewpoint(bpy.types.Operator): if viewpoint.bitmaps: self.create_bitmaps(bcfxml, viewpoint, topic) - self.setup_camera(viewpoint, obj, cam_aspect) + self.setup_camera(viewpoint, obj, cam_aspect, context) return {"FINISHED"} - def setup_camera(self, viewpoint, obj, cam_aspect): + def setup_camera(self, viewpoint, obj, cam_aspect, context): if viewpoint.orthogonal_camera: camera = viewpoint.orthogonal_camera obj.data.type = "ORTHO" @@ -748,7 +852,7 @@ class ActivateBcfViewpoint(bpy.types.Operator): [x_axis[2], y_axis[2], z_axis[2], camera.camera_view_point.z], [0, 0, 0, 1], )) - props = bpy.context.scene.BIMGeoreferenceProperties + props = context.scene.BIMGeoreferenceProperties if props.has_blender_offset: unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) matrix = ifcopenshell.util.geolocation.global2local( @@ -761,7 +865,7 @@ class ActivateBcfViewpoint(bpy.types.Operator): ) obj.matrix_world = Matrix(matrix.tolist()) - def set_viewpoint_components(self, viewpoint): + def set_viewpoint_components(self, viewpoint, context): if not viewpoint.components: return @@ -771,10 +875,10 @@ class ActivateBcfViewpoint(bpy.types.Operator): exception_global_ids = [v.ifc_guid for v in viewpoint.components.visibility.exceptions] if viewpoint.components.visibility.default_visibility: - old = bpy.context.area.type - bpy.context.area.type = "VIEW_3D" + old = context.area.type + context.area.type = "VIEW_3D" bpy.ops.object.hide_view_clear() - bpy.context.area.type = old + context.area.type = old for global_id in exception_global_ids: obj = IfcStore.get_element(global_id) if obj: @@ -786,35 +890,35 @@ class ActivateBcfViewpoint(bpy.types.Operator): if obj: objs.append(obj) if objs: - old = bpy.context.area.type - bpy.context.area.type = "VIEW_3D" + old = context.area.type + context.area.type = "VIEW_3D" context_override = {} context_override["object"] = context_override["active_object"] = objs[0] context_override["selected_objects"] = context_override["selected_editable_objects"] = objs bpy.ops.object.hide_view_set(context_override, unselected=True) - bpy.context.area.type = old + context.area.type = old if viewpoint.components.view_setup_hints: if not viewpoint.components.view_setup_hints.spaces_visible: - self.hide_spaces() + self.hide_spaces(context) if viewpoint.components.view_setup_hints.openings_visible is not None: - self.set_openings_visibility(viewpoint.components.view_setup_hints.openings_visible) + self.set_openings_visibility(viewpoint.components.view_setup_hints.openings_visible, context) else: - self.hide_spaces() - self.set_openings_visibility(False) + self.hide_spaces(context) + self.set_openings_visibility(False, context) self.set_selection(viewpoint) self.set_colours(viewpoint) - def hide_spaces(self): - old = bpy.context.area.type - bpy.context.area.type = "VIEW_3D" + def hide_spaces(self, context): + old = context.area.type + context.area.type = "VIEW_3D" bpy.ops.object.select_pattern(pattern="IfcSpace/*") bpy.ops.object.hide_view_set({}) - bpy.context.area.type = old + context.area.type = old - def set_openings_visibility(self, is_visible): - for collection in self.get_opening_collections(): + def set_openings_visibility(self, is_visible, context): + for collection in self.get_opening_collections(context): collection.hide_viewport = not is_visible def set_selection(self, viewpoint): @@ -835,9 +939,9 @@ class ActivateBcfViewpoint(bpy.types.Operator): if obj: obj.color = self.hex_to_rgb(color) - def get_opening_collections(self): + def get_opening_collections(self, context): collections = [] - for collection in bpy.context.view_layer.layer_collection.children: + for collection in context.view_layer.layer_collection.children: opening_collection = collection.children.get("IfcOpeningElements") if opening_collection: collections.append(opening_collection) @@ -939,9 +1043,7 @@ class SelectBcfHeaderFile(bpy.types.Operator): def execute(self, context): if self.filepath: - props = context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.file_reference = self.filepath + context.scene.BCFProperties.file_reference = self.filepath return {"FINISHED"} def invoke(self, context, event): @@ -957,9 +1059,7 @@ class SelectBcfBimSnippetReference(bpy.types.Operator): def execute(self, context): if self.filepath: - props = context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.bim_snippet_reference = self.filepath + context.scene.BCFProperties.bim_snippet_reference = self.filepath return {"FINISHED"} def invoke(self, context, event): @@ -975,9 +1075,7 @@ class SelectBcfDocumentReference(bpy.types.Operator): def execute(self, context): if self.filepath: - props = context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.document_reference = self.filepath + context.scene.BCFProperties.document_reference = self.filepath return {"FINISHED"} def invoke(self, context, event): diff --git a/src/blenderbim/blenderbim/bim/module/bcf/prop.py b/src/blenderbim/blenderbim/bim/module/bcf/prop.py index f64ec46382..8f20938e64 100644 --- a/src/blenderbim/blenderbim/bim/module/bcf/prop.py +++ b/src/blenderbim/blenderbim/bim/module/bcf/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import bcfstore from blenderbim.bim.prop import StrProperty @@ -33,12 +52,12 @@ def updateBcfLabel(self, context): def updateBcfProjectName(self, context): - if context.scene.BCFProperties.is_loaded: + if self.is_loaded: bpy.ops.bim.edit_bcf_project_name() def updateBcfAuthor(self, context): - if context.scene.BCFProperties.is_loaded: + if self.is_loaded: bpy.ops.bim.edit_bcf_author() @@ -58,14 +77,8 @@ def updateBcfCommentIsEditable(self, context): def refreshBcfTopic(self, context): - global bcfviewpoints_enum - bcfviewpoints_enum = None - - props = context.scene.BCFProperties - bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = props.topics[props.active_topic_index] - header = bcfxml.get_header(topic.name) - getBcfViewpoints(self, context) + self.clear_input_fields() + getBcfViewpoints(None, context, force_update=True) class BcfReferenceLink(PropertyGroup): @@ -76,13 +89,13 @@ class BcfLabel(PropertyGroup): name: StringProperty(name="Name", update=updateBcfLabel) -def getBcfViewpoints(self, context): +def getBcfViewpoints(self, context, force_update=False): global bcfviewpoints_enum - if bcfviewpoints_enum is None: + if bcfviewpoints_enum is None or force_update: # Retrieving Viewpoints is slow. Make sure we only do when needed bcfviewpoints_enum = [] props = context.scene.BCFProperties bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = props.topics[props.active_topic_index] + topic = props.active_topic viewpoints = bcfxml.get_viewpoints(topic.name) bcfviewpoints_enum.extend([(v, f"Viewpoint {i+1}", "") for i, v in enumerate(viewpoints.keys())]) return bcfviewpoints_enum @@ -127,28 +140,15 @@ class BcfTopic(PropertyGroup): 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") + viewpoints: EnumProperty(items=lambda _, context: getBcfViewpoints(_, context), 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): @@ -158,3 +158,44 @@ class BCFProperties(PropertyGroup): 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) + 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_link: StringProperty(default="", name="Reference Link") + label: StringProperty(default="", name="Label") + bim_snippet_reference: StringProperty(default="", name="Reference") + bim_snippet_type: StringProperty(default="", name="Type") + bim_snippet_schema: StringProperty(default="", name="Schema") + document_reference: StringProperty(default="", name="Referenced Document") + document_reference_description: StringProperty(default="", name="Description") + related_topic: StringProperty(name="Related Topic") + comment: StringProperty(default="", name="Comment") + has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False) + + def clear_input_fields(self): + self.file_reference = "" + self.file_ifc_project = "" + self.file_ifc_spatial_structure_element = "" + self.reference_link = "" + self.label = "" + self.bim_snippet_reference = "" + self.bim_snippet_type = "" + self.bim_snippet_schema = "" + self.document_reference = "" + self.document_reference_description = "" + self.related_topic = "" + self.comment = "" + self.has_related_viewpoint = False + + @property + def active_topic(self): + if len(self.topics) == 0: + return None + if self.active_topic_index < 0: + self.active_topic_index = 0 + if self.active_topic_index >= len(self.topics): + self.active_topic_index = len(self.topics) - 1 + return self.topics[self.active_topic_index] + + def refresh_topic(self, context): + refreshBcfTopic(self, context) diff --git a/src/blenderbim/blenderbim/bim/module/bcf/ui.py b/src/blenderbim/blenderbim/bim/module/bcf/ui.py index f90983d609..dfa8de1aa6 100644 --- a/src/blenderbim/blenderbim/bim/module/bcf/ui.py +++ b/src/blenderbim/blenderbim/bim/module/bcf/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy from . import bcfstore @@ -39,12 +58,13 @@ class BIM_PT_bcf(Panel): 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="") + col.operator("bim.remove_bcf_topic", icon="REMOVE", text="") if props.active_topic_index < len(props.topics): - topic = props.topics[props.active_topic_index] + topic = props.active_topic 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] + topic = props.active_topic row = layout.row() row.enabled = topic.is_editable row.prop(topic, "description", text="") @@ -99,7 +119,7 @@ class BIM_PT_bcf_metadata(Panel): layout.label(text="No BCF project is loaded") return - topic = props.topics[props.active_topic_index] + topic = props.active_topic bcfxml = bcfstore.BcfStore.get_bcfxml() bcf_topic = bcfxml.topics[topic.name] @@ -132,12 +152,12 @@ class BIM_PT_bcf_metadata(Panel): row.label(text=f.ifc_spatial_structure_element) row = layout.row(align=True) - row.prop(topic, "file_reference") + row.prop(props, "file_reference") row.operator("bim.select_bcf_header_file", icon="FILE_FOLDER", text="") row = layout.row() - row.prop(topic, "file_ifc_project") + row.prop(props, "file_ifc_project") row = layout.row() - row.prop(topic, "file_ifc_spatial_structure_element") + row.prop(props, "file_ifc_spatial_structure_element") row = layout.row() row.operator("bim.add_bcf_header_file") @@ -149,7 +169,7 @@ class BIM_PT_bcf_metadata(Panel): 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.prop(props, "reference_link") row = layout.row() row.operator("bim.add_bcf_reference_link") @@ -159,7 +179,7 @@ class BIM_PT_bcf_metadata(Panel): row.prop(label, "name", text="") row.operator("bim.remove_bcf_label", icon="X", text="").index = index row = layout.row() - row.prop(topic, "label") + row.prop(props, "label") row = layout.row() row.operator("bim.add_bcf_label") @@ -180,12 +200,12 @@ class BIM_PT_bcf_metadata(Panel): row.operator("bim.remove_bcf_bim_snippet", icon="X", text="") else: row = layout.row(align=True) - row.prop(topic, "bim_snippet_reference") + row.prop(props, "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.prop(props, "bim_snippet_type") row = layout.row() - row.prop(topic, "bim_snippet_schema") + row.prop(props, "bim_snippet_schema") row = layout.row() row.operator("bim.add_bcf_bim_snippet") @@ -203,20 +223,26 @@ class BIM_PT_bcf_metadata(Panel): row = box.row(align=True) row.prop(doc, "description") row = layout.row(align=True) - row.prop(topic, "document_reference") + row.prop(props, "document_reference") row.operator("bim.select_bcf_document_reference", icon="FILE_FOLDER", text="") row = layout.row() - row.prop(topic, "document_reference_description") + row.prop(props, "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 + for index, related_topic in enumerate(topic.related_topics): + try: + row = layout.row(align=True) + op = row.operator( + "bim.view_bcf_topic", + text=f"Select {bcfxml.topics[related_topic.name.lower()].title}") + op.topic_guid = related_topic.name + row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index + except KeyError: + pass row = layout.row() - row.prop(topic, "related_topic") + row.prop(props, "related_topic") row = layout.row() row.operator("bim.add_bcf_related_topic") @@ -245,7 +271,7 @@ class BIM_PT_bcf_comments(Panel): row = layout.row() row.prop(props, "comment_text_width") - topic = props.topics[props.active_topic_index] + topic = props.active_topic for comment in topic.comments: box = self.layout.box() @@ -276,8 +302,8 @@ class BIM_PT_bcf_comments(Panel): col.label(text=" ".join(line_words)) row = layout.row() - row.prop(topic, "comment") + row.prop(props, "comment") row = layout.row() - row.prop(topic, "has_related_viewpoint") + row.prop(props, "has_related_viewpoint") row = layout.row() row.operator("bim.add_bcf_comment") diff --git a/src/blenderbim/blenderbim/bim/module/bimtester/__init__.py b/src/blenderbim/blenderbim/bim/module/bimtester/__init__.py index 42feab2dcb..a9793f5c5d 100644 --- a/src/blenderbim/blenderbim/bim/module/bimtester/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/bimtester/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/bimtester/operator.py b/src/blenderbim/blenderbim/bim/module/bimtester/operator.py index 150ef4c5c0..7bf9905313 100644 --- a/src/blenderbim/blenderbim/bim/module/bimtester/operator.py +++ b/src/blenderbim/blenderbim/bim/module/bimtester/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import tempfile @@ -20,6 +39,11 @@ class ExecuteBIMTester(bpy.types.Operator): bl_idname = "bim.execute_bim_tester" bl_label = "Execute BIMTester" + @classmethod + def poll(cls, context): + props = context.scene.BimTesterProperties + return props.ifc_file and props.feature + def execute(self, context): props = context.scene.BimTesterProperties diff --git a/src/blenderbim/blenderbim/bim/module/bimtester/prop.py b/src/blenderbim/blenderbim/bim/module/bimtester/prop.py index db245767c7..1518ea234e 100644 --- a/src/blenderbim/blenderbim/bim/module/bimtester/prop.py +++ b/src/blenderbim/blenderbim/bim/module/bimtester/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os from pathlib import Path from blenderbim.bim.prop import StrProperty diff --git a/src/blenderbim/blenderbim/bim/module/bimtester/ui.py b/src/blenderbim/blenderbim/bim/module/bimtester/ui.py index b1508ad84f..af557c77fc 100644 --- a/src/blenderbim/blenderbim/bim/module/bimtester/ui.py +++ b/src/blenderbim/blenderbim/bim/module/bimtester/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/boundary/__init__.py b/src/blenderbim/blenderbim/bim/module/boundary/__init__.py index aab371b6fe..32c66b3b15 100644 --- a/src/blenderbim/blenderbim/bim/module/boundary/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/boundary/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui diff --git a/src/blenderbim/blenderbim/bim/module/boundary/ui.py b/src/blenderbim/blenderbim/bim/module/boundary/ui.py index 4e0886a054..f401fbdc0b 100644 --- a/src/blenderbim/blenderbim/bim/module/boundary/ui.py +++ b/src/blenderbim/blenderbim/bim/module/boundary/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import blenderbim.bim.helper from bpy.types import Panel, UIList diff --git a/src/blenderbim/blenderbim/bim/module/clash/__init__.py b/src/blenderbim/blenderbim/bim/module/clash/__init__.py index 63448c96e3..8dcca175c7 100644 --- a/src/blenderbim/blenderbim/bim/module/clash/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/clash/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/clash/operator.py b/src/blenderbim/blenderbim/bim/module/clash/operator.py index 45b9f5cecf..90223e46d4 100644 --- a/src/blenderbim/blenderbim/bim/module/clash/operator.py +++ b/src/blenderbim/blenderbim/bim/module/clash/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json @@ -6,6 +25,7 @@ import logging import numpy as np from mathutils import Matrix from math import radians +from blenderbim.bim.ifc import IfcStore class ExportClashSets(bpy.types.Operator): @@ -105,7 +125,7 @@ class AddClashSource(bpy.types.Operator): group: bpy.props.StringProperty() def execute(self, context): - clash_set = context.scene.BIMClashProperties.clash_sets[context.scene.BIMClashProperties.active_clash_set_index] + clash_set = context.scene.BIMClashProperties.active_clash_set source = getattr(clash_set, self.group).add() return {"FINISHED"} @@ -118,7 +138,7 @@ class RemoveClashSource(bpy.types.Operator): group: bpy.props.StringProperty() def execute(self, context): - clash_set = context.scene.BIMClashProperties.clash_sets[context.scene.BIMClashProperties.active_clash_set_index] + clash_set = context.scene.BIMClashProperties.active_clash_set getattr(clash_set, self.group).remove(self.index) return {"FINISHED"} @@ -133,7 +153,7 @@ class SelectClashSource(bpy.types.Operator): group: bpy.props.StringProperty() def execute(self, context): - clash_set = context.scene.BIMClashProperties.clash_sets[context.scene.BIMClashProperties.active_clash_set_index] + clash_set = context.scene.BIMClashProperties.active_clash_set getattr(clash_set, self.group)[self.index].name = self.filepath return {"FINISHED"} @@ -257,9 +277,7 @@ class SelectIfcClashResults(bpy.types.Operator): self.filepath = bpy.path.ensure_ext(self.filepath, ".json") with open(self.filepath) as f: clash_sets = json.load(f) - clash_set_name = context.scene.BIMClashProperties.clash_sets[ - context.scene.BIMClashProperties.active_clash_set_index - ].name + clash_set_name = context.scene.BIMClashProperties.active_clash_set.name global_ids = [] for clash_set in clash_sets: if clash_set["name"] != clash_set_name: @@ -284,6 +302,10 @@ class SmartClashGroup(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} filepath: bpy.props.StringProperty(subtype="FILE_PATH") + @classmethod + def poll(cls, context): + return context.scene.BIMClashProperties.clash_results_path + def execute(self, context): import ifcclash @@ -307,9 +329,7 @@ class SmartClashGroup(bpy.types.Operator): with open(save_path, "w") as f: f.write(json.dumps(smart_grouped_clashes)) - clash_set_name = context.scene.BIMClashProperties.clash_sets[ - context.scene.BIMClashProperties.active_clash_set_index - ].name + clash_set_name = context.scene.BIMClashProperties.active_clash_set.name # Reset the list of smart_clash_groups for the UI context.scene.BIMClashProperties.smart_clash_groups.clear() @@ -336,12 +356,14 @@ class LoadSmartGroupsForActiveClashSet(bpy.types.Operator): bl_label = "Load Smart Groups for Active Clash Set" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.scene.BIMClashProperties.active_clash_set + def execute(self, context): smart_groups_path = bpy.path.ensure_ext(context.scene.BIMClashProperties.smart_grouped_clashes_path, ".json") - clash_set_name = context.scene.BIMClashProperties.clash_sets[ - context.scene.BIMClashProperties.active_clash_set_index - ].name + clash_set_name = context.scene.BIMClashProperties.active_clash_set.name with open(smart_groups_path) as f: smart_grouped_clashes = json.load(f) @@ -370,11 +392,14 @@ class SelectSmartGroup(bpy.types.Operator): bl_label = "Select Smart Group" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return IfcStore.get_file() and context.visible_objects and context.scene.BIMClashProperties.active_smart_group + def execute(self, context): + self.file = IfcStore.get_file() # Select smart group in view - selected_smart_group = context.scene.BIMClashProperties.smart_clash_groups[ - context.scene.BIMCLashProperties.active_smart_group_index - ] + selected_smart_group = context.scene.BIMClashProperties.active_smart_group # print(selected_smart_group.number) for obj in context.visible_objects: @@ -440,8 +465,7 @@ class SetBlenderClashSetA(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - while len(context.scene.BIMClashProperties.blender_clash_set_a) > 0: - context.scene.BIMClashProperties.blender_clash_set_a.remove(0) + context.scene.BIMClashProperties.blender_clash_set_a.clear() for obj in context.selected_objects: new = context.scene.BIMClashProperties.blender_clash_set_a.add() new.name = obj.name @@ -454,8 +478,7 @@ class SetBlenderClashSetB(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - while len(context.scene.BIMClashProperties.blender_clash_set_b) > 0: - context.scene.BIMClashProperties.blender_clash_set_b.remove(0) + context.scene.BIMClashProperties.blender_clash_set_b.clear() for obj in context.selected_objects: new = context.scene.BIMClashProperties.blender_clash_set_b.add() new.name = obj.name diff --git a/src/blenderbim/blenderbim/bim/module/clash/prop.py b/src/blenderbim/blenderbim/bim/module/clash/prop.py index 8dcb14594b..e721db86ce 100644 --- a/src/blenderbim/blenderbim/bim/module/clash/prop.py +++ b/src/blenderbim/blenderbim/bim/module/clash/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup @@ -50,3 +69,15 @@ class BIMClashProperties(PropertyGroup): smart_clash_grouping_max_distance: IntProperty( name="Smart Clash Grouping Max Distance", default=3, soft_min=1, soft_max=10 ) + + @property + def active_clash_set(self): + if not self.clash_sets: + return None + return self.clash_sets[self.active_clash_set_index] + + @property + def active_smart_group(self): + if not self.smart_clash_groups: + return None + return self.smart_clash_groups[self.active_smart_group_index] diff --git a/src/blenderbim/blenderbim/bim/module/clash/ui.py b/src/blenderbim/blenderbim/bim/module/clash/ui.py index a6a37a7680..9b6d021a42 100644 --- a/src/blenderbim/blenderbim/bim/module/clash/ui.py +++ b/src/blenderbim/blenderbim/bim/module/clash/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel @@ -38,7 +57,7 @@ class BIM_PT_ifcclash(Panel): layout.template_list("BIM_UL_clash_sets", "", props, "clash_sets", props, "active_clash_set_index") if props.active_clash_set_index < len(props.clash_sets): - clash_set = props.clash_sets[props.active_clash_set_index] + clash_set = props.active_clash_set row = layout.row(align=True) row.prop(clash_set, "name") diff --git a/src/blenderbim/blenderbim/bim/module/classification/__init__.py b/src/blenderbim/blenderbim/bim/module/classification/__init__.py index f486b4e3fa..f03523e884 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/classification/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/classification/operator.py b/src/blenderbim/blenderbim/bim/module/classification/operator.py index 7603b09d04..b1dd53b8fd 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/operator.py +++ b/src/blenderbim/blenderbim/bim/module/classification/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -50,8 +69,7 @@ class EnableEditingClassification(bpy.types.Operator): def execute(self, context): props = context.scene.BIMClassificationProperties - while len(props.classification_attributes) > 0: - props.classification_attributes.remove(0) + props.classification_attributes.clear() classification_data = Data.classifications[self.classification] for attribute in IfcStore.get_schema().declaration_by_name("IfcClassification").all_attributes(): new = props.classification_attributes.add() @@ -135,8 +153,7 @@ class EnableEditingClassificationReference(bpy.types.Operator): def execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object props = obj.BIMClassificationReferenceProperties - while len(props.reference_attributes) > 0: - props.reference_attributes.remove(0) + props.reference_attributes.clear() reference_data = Data.references[self.reference] for attribute in IfcStore.get_schema().declaration_by_name("IfcClassificationReference").all_attributes(): if attribute.name() == "ReferencedSource": diff --git a/src/blenderbim/blenderbim/bim/module/classification/prop.py b/src/blenderbim/blenderbim/bim/module/classification/prop.py index 932335a3a3..e760b5eb47 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/prop.py +++ b/src/blenderbim/blenderbim/bim/module/classification/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from ifcopenshell.api.classification.data import Data @@ -37,8 +56,7 @@ def updateClassification(self, context): def getReferences(self, context, parent_id=None): props = context.scene.BIMClassificationProperties - while len(props.available_library_references) > 0: - props.available_library_references.remove(0) + props.available_library_references.clear() for reference in Data.library_file.by_id(parent_id).HasReferences: new = props.available_library_references.add() new.identification = reference.Identification or "" diff --git a/src/blenderbim/blenderbim/bim/module/classification/ui.py b/src/blenderbim/blenderbim/bim/module/classification/ui.py index efcdc6c42e..cdc6357589 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/ui.py +++ b/src/blenderbim/blenderbim/bim/module/classification/ui.py @@ -1,3 +1,23 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.bim.module.classification.prop as classification_prop from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.classification.data import Data @@ -85,7 +105,7 @@ class BIM_PT_classification_references(Panel): if self.oprops.ifc_definition_id not in Data.products: Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id) - self.draw_add_ui() + self.draw_add_ui(context) reference_ids = Data.products[self.oprops.ifc_definition_id] if not reference_ids: @@ -99,8 +119,8 @@ class BIM_PT_classification_references(Panel): else: self.draw_ui(reference_id, reference) - def draw_add_ui(self): - if not self.sprops.available_classifications: + def draw_add_ui(self, context): + if not classification_prop.getClassifications(self.sprops, context): return name = Data.library_classifications[int(self.sprops.available_classifications)] @@ -127,7 +147,7 @@ class BIM_PT_classification_references(Panel): row = self.layout.row(align=True) row.prop(self.props.reference_attributes.get("Name"), "string_value", text="", icon="ASSET_MANAGER") row.operator("bim.edit_classification_reference", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_classification_reference", text="", icon="X") + row.operator("bim.disable_editing_classification_reference", text="", icon="CANCEL") for attribute in self.props.reference_attributes: if attribute.name == "Name": diff --git a/src/blenderbim/blenderbim/bim/module/cobie/__init__.py b/src/blenderbim/blenderbim/bim/module/cobie/__init__.py index 46ec55b5b6..55ce5b8358 100644 --- a/src/blenderbim/blenderbim/bim/module/cobie/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cobie/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/cobie/operator.py b/src/blenderbim/blenderbim/bim/module/cobie/operator.py index 6d8221189a..58022975a8 100644 --- a/src/blenderbim/blenderbim/bim/module/cobie/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cobie/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import os import logging @@ -43,14 +62,19 @@ class ExecuteIfcCobie(bpy.types.Operator): bl_label = "Execute IFCCOBie" file_format: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + props = context.scene.COBieProperties + return props.should_load_from_memory or props.cobie_ifc_file + def execute(self, context): from cobie import IfcCobieParser props = context.scene.COBieProperties - - output_dir = os.path.dirname(props.cobie_ifc_file) - + if props.should_load_from_memory: output_dir = tempfile.gettempdir() + else: + output_dir = os.path.dirname(props.cobie_ifc_file) output = os.path.join(output_dir, "output") logger = logging.getLogger("IFCtoCOBie") diff --git a/src/blenderbim/blenderbim/bim/module/cobie/prop.py b/src/blenderbim/blenderbim/bim/module/cobie/prop.py index 095622298f..0eb6788f79 100644 --- a/src/blenderbim/blenderbim/bim/module/cobie/prop.py +++ b/src/blenderbim/blenderbim/bim/module/cobie/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import PropertyGroup from bpy.props import ( diff --git a/src/blenderbim/blenderbim/bim/module/cobie/ui.py b/src/blenderbim/blenderbim/bim/module/cobie/ui.py index cbce5b033e..c311e58e26 100644 --- a/src/blenderbim/blenderbim/bim/module/cobie/ui.py +++ b/src/blenderbim/blenderbim/bim/module/cobie/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/constraint/__init__.py b/src/blenderbim/blenderbim/bim/module/constraint/__init__.py index 190ce3fe12..8469bd48bf 100644 --- a/src/blenderbim/blenderbim/bim/module/constraint/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/constraint/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/constraint/operator.py b/src/blenderbim/blenderbim/bim/module/constraint/operator.py index a5be6e3674..d7b409fa93 100644 --- a/src/blenderbim/blenderbim/bim/module/constraint/operator.py +++ b/src/blenderbim/blenderbim/bim/module/constraint/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -14,8 +33,7 @@ class LoadObjectives(bpy.types.Operator): def execute(self, context): props = context.scene.BIMConstraintProperties - while len(props.constraints) > 0: - props.constraints.remove(0) + props.constraints.clear() for constraint_id, constraint in Data.objectives.items(): new = props.constraints.add() new.name = constraint["Name"] or "Unnamed" @@ -44,8 +62,7 @@ class EnableEditingConstraint(bpy.types.Operator): def execute(self, context): props = context.scene.BIMConstraintProperties - while len(props.constraint_attributes) > 0: - props.constraint_attributes.remove(0) + props.constraint_attributes.clear() if props.is_editing == "IfcObjective": data = Data.objectives[self.constraint] diff --git a/src/blenderbim/blenderbim/bim/module/constraint/prop.py b/src/blenderbim/blenderbim/bim/module/constraint/prop.py index b4474db3d1..3bd87458ec 100644 --- a/src/blenderbim/blenderbim/bim/module/constraint/prop.py +++ b/src/blenderbim/blenderbim/bim/module/constraint/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/constraint/ui.py b/src/blenderbim/blenderbim/bim/module/constraint/ui.py index 2a0ae2d6cd..5264196e75 100644 --- a/src/blenderbim/blenderbim/bim/module/constraint/ui.py +++ b/src/blenderbim/blenderbim/bim/module/constraint/ui.py @@ -1,5 +1,25 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes from ifcopenshell.api.constraint.data import Data @@ -44,14 +64,7 @@ class BIM_PT_constraints(Panel): self.draw_editable_ui(context) def draw_editable_ui(self, context): - for attribute in self.props.constraint_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.constraint_attributes, self.layout) class BIM_PT_object_constraints(Panel): @@ -102,7 +115,7 @@ class BIM_PT_object_constraints(Panel): row = self.layout.row(align=True) icon = "LIGHT" if self.props.is_adding == "IfcObjective" else "FILE_HIDDEN" row.label(text="Adding {}".format(self.props.is_adding), icon=icon) - row.operator("bim.disable_assigning_constraint", text="", icon="X") + row.operator("bim.disable_assigning_constraint", text="", icon="CANCEL") self.layout.template_list( "BIM_UL_object_constraints", "", @@ -125,7 +138,7 @@ class BIM_UL_constraints(UIList): if context.scene.BIMConstraintProperties.active_constraint_id == item.ifc_definition_id: if context.scene.BIMConstraintProperties.is_editing == "IfcObjective": row.operator("bim.edit_objective", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_constraint", text="", icon="X") + row.operator("bim.disable_editing_constraint", text="", icon="CANCEL") elif context.scene.BIMConstraintProperties.active_constraint_id: row.operator("bim.remove_constraint", text="", icon="X").constraint = item.ifc_definition_id else: diff --git a/src/blenderbim/blenderbim/bim/module/context/__init__.py b/src/blenderbim/blenderbim/bim/module/context/__init__.py index fa07da07e8..f4fbdab85e 100644 --- a/src/blenderbim/blenderbim/bim/module/context/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/context/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, operator diff --git a/src/blenderbim/blenderbim/bim/module/context/operator.py b/src/blenderbim/blenderbim/bim/module/context/operator.py index 9936e1787c..263967f774 100644 --- a/src/blenderbim/blenderbim/bim/module/context/operator.py +++ b/src/blenderbim/blenderbim/bim/module/context/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/context/ui.py b/src/blenderbim/blenderbim/bim/module/context/ui.py index 2573cfa80f..614795bb8d 100644 --- a/src/blenderbim/blenderbim/bim/module/context/ui.py +++ b/src/blenderbim/blenderbim/bim/module/context/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from ifcopenshell.api.context.data import Data from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/cost/__init__.py b/src/blenderbim/blenderbim/bim/module/cost/__init__.py index fa370240d8..c768025826 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cost/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator @@ -26,6 +45,8 @@ classes = ( operator.ExpandCostItem, operator.ContractCostItem, operator.RemoveCostItem, + operator.AssignCostItemType, + operator.UnassignCostItemType, operator.AssignCostItemQuantity, operator.UnassignCostItemQuantity, operator.AddCostItemQuantity, @@ -37,14 +58,24 @@ classes = ( operator.SelectCostScheduleProducts, operator.ImportCostScheduleCsv, operator.LoadCostItemQuantities, + operator.LoadCostItemTypes, + operator.AssignCostValue, + operator.LoadScheduleOfRates, + operator.ExpandCostItemRate, + operator.ContractCostItemRate, prop.CostItem, prop.CostItemQuantity, + prop.CostItemType, prop.BIMCostProperties, ui.BIM_PT_cost_schedules, ui.BIM_PT_cost_item_quantities, + ui.BIM_PT_cost_item_types, + ui.BIM_PT_cost_item_rates, ui.BIM_UL_cost_items, ui.BIM_UL_cost_columns, ui.BIM_UL_cost_item_quantities, + ui.BIM_UL_cost_item_types, + ui.BIM_UL_cost_item_rates, ) diff --git a/src/blenderbim/blenderbim/bim/module/cost/operator.py b/src/blenderbim/blenderbim/bim/module/cost/operator.py index 766c9941bc..96bd5cd595 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cost/operator.py @@ -1,3 +1,21 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json @@ -43,6 +61,7 @@ class EditCostSchedule(bpy.types.Operator): **{"cost_schedule": self.file.by_id(props.active_cost_schedule_id), "attributes": attributes}, ) Data.load(IfcStore.get_file()) + purge() bpy.ops.bim.disable_editing_cost_schedule() return {"FINISHED"} @@ -75,8 +94,7 @@ class EnableEditingCostSchedule(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMCostProperties self.props.active_cost_schedule_id = self.cost_schedule - while len(self.props.cost_schedule_attributes) > 0: - self.props.cost_schedule_attributes.remove(0) + self.props.cost_schedule_attributes.clear() self.enable_editing_cost_schedule() self.props.is_editing = "COST_SCHEDULE" return {"FINISHED"} @@ -105,8 +123,7 @@ class EnableEditingCostItems(bpy.types.Operator): self.props = context.scene.BIMCostProperties self.props.is_cost_update_enabled = False self.props.active_cost_schedule_id = self.cost_schedule - while len(self.props.cost_items) > 0: - self.props.cost_items.remove(0) + self.props.cost_items.clear() self.contracted_cost_items = json.loads(self.props.contracted_cost_items) for related_object_id in Data.cost_schedules[self.cost_schedule]["Controls"]: @@ -145,8 +162,6 @@ class EnableEditingCostItems(bpy.types.Operator): for related_object_id in cost_item["IsNestedBy"]: self.create_new_cost_item_li(related_object_id, level_index + 1) - return {"FINISHED"} - class DisableEditingCostSchedule(bpy.types.Operator): bl_idname = "bim.disable_editing_cost_schedule" @@ -260,8 +275,7 @@ class EnableEditingCostItem(bpy.types.Operator): def execute(self, context): props = context.scene.BIMCostProperties - while len(props.cost_item_attributes) > 0: - props.cost_item_attributes.remove(0) + props.cost_item_attributes.clear() data = Data.cost_items[self.cost_item] blenderbim.bim.helper.import_attributes("IfcCostItem", props.cost_item_attributes, data) @@ -303,6 +317,63 @@ class EditCostItem(bpy.types.Operator): return {"FINISHED"} +class AssignCostItemType(bpy.types.Operator): + bl_idname = "bim.assign_cost_item_type" + bl_label = "Assign Cost Item Type Product" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + prop_name: bpy.props.StringProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + cost_item = self.file.by_id(self.cost_item) + for obj in context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + if product.is_a("IfcTypeProduct"): + ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=cost_item, related_object=product + ) + Data.load(self.file) + bpy.ops.bim.load_cost_item_types() + return {"FINISHED"} + + +class UnassignCostItemType(bpy.types.Operator): + bl_idname = "bim.unassign_cost_item_type" + bl_label = "Unassign Cost Item Type" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + related_object: bpy.props.IntProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + cost_item = self.file.by_id(self.cost_item) + if self.related_object: + products = [self.file.by_id(self.related_object)] + else: + for obj in context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + if product.is_a("IfcTypeProduct"): + products.append(product) + for product in products: + ifcopenshell.api.run( + "control.unassign_control", self.file, relating_control=cost_item, related_object=product + ) + Data.load(self.file) + bpy.ops.bim.load_cost_item_types() + return {"FINISHED"} + + class AssignCostItemQuantity(bpy.types.Operator): bl_idname = "bim.assign_cost_item_quantity" bl_label = "Assign Cost Item Quantity" @@ -367,7 +438,7 @@ class UnassignCostItemQuantity(bpy.types.Operator): else: products = [ self.file.by_id(o.BIMObjectProperties.ifc_definition_id) - for o in bpy.context.selected_objects + for o in context.selected_objects if o.BIMObjectProperties.ifc_definition_id ] ifcopenshell.api.run( @@ -465,8 +536,7 @@ class EnableEditingCostItemQuantity(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMCostProperties - while len(self.props.quantity_attributes) > 0: - self.props.quantity_attributes.remove(0) + self.props.quantity_attributes.clear() self.props.active_cost_item_quantity_id = self.physical_quantity data = Data.physical_quantities[self.physical_quantity] blenderbim.bim.helper.import_attributes(data["type"], self.props.quantity_attributes, data) @@ -536,6 +606,7 @@ class RemoveCostItemValue(bpy.types.Operator): bl_idname = "bim.remove_cost_item_value" bl_label = "Add Cost Item Value" bl_options = {"REGISTER", "UNDO"} + parent: bpy.props.IntProperty() cost_value: bpy.props.IntProperty() def execute(self, context): @@ -543,7 +614,12 @@ class RemoveCostItemValue(bpy.types.Operator): def _execute(self, context): self.file = IfcStore.get_file() - ifcopenshell.api.run("cost.remove_cost_item_value", self.file, cost_value=self.file.by_id(self.cost_value)) + ifcopenshell.api.run( + "cost.remove_cost_item_value", + self.file, + parent=self.file.by_id(self.parent), + cost_value=self.file.by_id(self.cost_value), + ) Data.load(self.file) return {"FINISHED"} @@ -556,17 +632,19 @@ class EnableEditingCostItemValue(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMCostProperties - while len(self.props.cost_value_attributes) > 0: - self.props.cost_value_attributes.remove(0) + self.props.cost_value_attributes.clear() self.props.active_cost_item_value_id = self.cost_value data = Data.cost_values[self.cost_value] blenderbim.bim.helper.import_attributes( - data["type"], self.props.cost_value_attributes, data, self.import_attributes + data["type"], + self.props.cost_value_attributes, + data, + lambda name, prop, data: self.import_attributes(name, prop, data, context) ) return {"FINISHED"} - def import_attributes(self, name, prop, data): + def import_attributes(self, name, prop, data, context): if name == "AppliedValue": # TODO: for now, only support simple values prop.data_type = "float" @@ -574,7 +652,7 @@ class EnableEditingCostItemValue(bpy.types.Operator): return True if ( name == "UnitBasis" - and Data.cost_schedules[bpy.context.scene.BIMCostProperties.active_cost_schedule_id]["PredefinedType"] + and Data.cost_schedules[context.scene.BIMCostProperties.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES" ): prop = self.props.cost_value_attributes.add() @@ -586,17 +664,28 @@ class EnableEditingCostItemValue(bpy.types.Operator): prop.float_value = data["UnitBasis"]["ValueComponent"] or 0 else: prop.float_value = 0 + prop = self.props.cost_value_attributes.add() prop.name = "UnitBasisUnit" prop.data_type = "enum" prop.is_null = prop.is_optional = False units = {} for unit_id, unit in UnitData.units.items(): - if unit.get("UnitType", None) in ["AREAUNIT", "LENGTHUNIT", "TIMEUNIT", "VOLUMEUNIT", "MASSUNIT"]: - name = unit["Name"] - if unit.get("Prefix", None): - name = f"(unit['Prefix']) {name}" - units[unit_id] = f"{unit['UnitType']} / {name}" + if unit.get("UnitType", None) in [ + "AREAUNIT", + "LENGTHUNIT", + "TIMEUNIT", + "VOLUMEUNIT", + "MASSUNIT", + "USERDEFINED", + ]: + if unit["type"] == "IfcContextDependentUnit": + units[unit_id] = f"{unit['UnitType']} / {unit['Name']}" + else: + name = unit["Name"] + if unit.get("Prefix", None): + name = f"(unit['Prefix']) {name}" + units[unit_id] = f"{unit['UnitType']} / {name}" prop.enum_items = json.dumps(units) if data["UnitBasis"] and data["UnitBasis"]["UnitComponent"]: prop.enum_value = str(data["UnitBasis"]["UnitComponent"]) @@ -625,7 +714,9 @@ class EditCostValue(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMCostProperties - attributes = blenderbim.bim.helper.export_attributes(props.cost_value_attributes, self.export_attributes) + attributes = blenderbim.bim.helper.export_attributes( + props.cost_value_attributes, + lambda attributes, prop: self.export_attributes(attributes, prop, context)) self.file = IfcStore.get_file() ifcopenshell.api.run( "cost.edit_cost_value", @@ -636,7 +727,7 @@ class EditCostValue(bpy.types.Operator): bpy.ops.bim.disable_editing_cost_item_value() return {"FINISHED"} - def export_attributes(self, attributes, prop): + def export_attributes(self, attributes, prop, context): if prop.name == "UnitBasisValue": if prop.is_null: attributes["UnitBasis"] = None @@ -644,7 +735,7 @@ class EditCostValue(bpy.types.Operator): attributes["UnitBasis"] = { "ValueComponent": prop.float_value or 1, "UnitComponent": IfcStore.get_file().by_id( - int(bpy.context.scene.BIMCostProperties.cost_value_attributes.get("UnitBasisUnit").enum_value) + int(context.scene.BIMCostProperties.cost_value_attributes.get("UnitBasisUnit").enum_value) ), } return True @@ -719,8 +810,12 @@ class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper): bl_options = {"REGISTER", "UNDO"} filename_ext = ".csv" filter_glob: bpy.props.StringProperty(default="*.csv", options={"HIDDEN"}) + is_schedule_of_rates: bpy.props.BoolProperty(name="Is Schedule Of Rates", default=False) def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): from ifc5d.csv2ifc import Csv2Ifc self.file = IfcStore.get_file() @@ -728,8 +823,11 @@ class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper): csv2ifc = Csv2Ifc() csv2ifc.csv = self.filepath csv2ifc.file = self.file + csv2ifc.is_schedule_of_rates = self.is_schedule_of_rates csv2ifc.execute() Data.load(IfcStore.get_file()) + UnitData.load(IfcStore.get_file()) + purge() print("Import finished in {:.2f} seconds".format(time.time() - start)) return {"FINISHED"} @@ -771,12 +869,9 @@ class LoadCostItemQuantities(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMCostProperties self.file = IfcStore.get_file() - while len(self.props.cost_item_products) > 0: - self.props.cost_item_products.remove(0) - while len(self.props.cost_item_processes) > 0: - self.props.cost_item_processes.remove(0) - while len(self.props.cost_item_resources) > 0: - self.props.cost_item_resources.remove(0) + self.props.cost_item_products.clear() + self.props.cost_item_processes.clear() + self.props.cost_item_resources.clear() ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id for control_id, quantity_ids in Data.cost_items[ifc_definition_id]["Controls"].items(): related_object = self.file.by_id(control_id) @@ -793,3 +888,115 @@ class LoadCostItemQuantities(bpy.types.Operator): total_quantity += self.file.by_id(quantity_id)[3] new.total_quantity = total_quantity return {"FINISHED"} + + +class LoadCostItemTypes(bpy.types.Operator): + bl_idname = "bim.load_cost_item_types" + bl_label = "Load Cost Item Types" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + self.props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + self.props.cost_item_type_products.clear() + # TODO implement process and resource types + # self.props.cost_item_processes.clear() + # self.props.cost_item_resources.clear() + ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id + for control_id, quantity_ids in Data.cost_items[ifc_definition_id]["Controls"].items(): + related_object = self.file.by_id(control_id) + if related_object.is_a("IfcTypeProduct"): + new = self.props.cost_item_type_products.add() + # TODO implement process and resource types + # elif related_object.is_a("IfcProcess"): + # new = self.props.cost_item_processes.add() + # elif related_object.is_a("IfcResource"): + # new = self.props.cost_item_resources.add() + new.ifc_definition_id = control_id + new.name = related_object.Name or "Unnamed" + return {"FINISHED"} + + +class AssignCostValue(bpy.types.Operator): + bl_idname = "bim.assign_cost_value" + bl_label = "Assign Cost Value" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + cost_rate: bpy.props.IntProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + ifcopenshell.api.run( + "cost.assign_cost_value", + self.file, + cost_item=self.file.by_id(self.cost_item), + cost_rate=self.file.by_id(self.cost_rate), + ) + Data.load(self.file) + return {"FINISHED"} + + +class LoadScheduleOfRates(bpy.types.Operator): + bl_idname = "bim.load_schedule_of_rates" + bl_label = "Load Schedule of Rates" + bl_options = {"REGISTER", "UNDO"} + cost_schedule: bpy.props.IntProperty() + + def execute(self, context): + self.props = context.scene.BIMCostProperties + self.props.is_cost_update_enabled = False + self.props.cost_item_rates.clear() + self.contracted_cost_item_rates = json.loads(self.props.contracted_cost_item_rates) + for related_object_id in Data.cost_schedules[self.cost_schedule]["Controls"]: + self.create_new_cost_item_li(related_object_id, 0) + self.props.is_cost_update_enabled = True + return {"FINISHED"} + + def create_new_cost_item_li(self, related_object_id, level_index): + cost_item = Data.cost_items[related_object_id] + new = self.props.cost_item_rates.add() + new.ifc_definition_id = related_object_id + new.name = cost_item["Name"] or "Unnamed" + new.identification = cost_item["Identification"] or "XXX" + new.is_expanded = related_object_id not in self.contracted_cost_item_rates + new.level_index = level_index + if cost_item["IsNestedBy"]: + new.has_children = True + if new.is_expanded: + for related_object_id in cost_item["IsNestedBy"]: + self.create_new_cost_item_li(related_object_id, level_index + 1) + + +class ExpandCostItemRate(bpy.types.Operator): + bl_idname = "bim.expand_cost_item_rate" + bl_label = "Expand Cost Item Rate" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + contracted_cost_item_rates = json.loads(props.contracted_cost_item_rates) + contracted_cost_item_rates.remove(self.cost_item) + props.contracted_cost_item_rates = json.dumps(contracted_cost_item_rates) + bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(props.schedule_of_rates)) + return {"FINISHED"} + + +class ContractCostItemRate(bpy.types.Operator): + bl_idname = "bim.contract_cost_item_rate" + bl_label = "Contract Cost Item Rate" + bl_options = {"REGISTER", "UNDO"} + cost_item: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + contracted_cost_item_rates = json.loads(props.contracted_cost_item_rates) + contracted_cost_item_rates.append(self.cost_item) + props.contracted_cost_item_rates = json.dumps(contracted_cost_item_rates) + bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(props.schedule_of_rates)) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/cost/prop.py b/src/blenderbim/blenderbim/bim/module/cost/prop.py index d57d373960..00a5ef18af 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/prop.py +++ b/src/blenderbim/blenderbim/bim/module/cost/prop.py @@ -1,3 +1,21 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from blenderbim.bim.ifc import IfcStore @@ -24,6 +42,7 @@ processquantitynames_enum = [] processquantitynames_id = 0 resourcequantitynames_enum = [] resourcequantitynames_id = 0 +scheduleofrates_enum = [] def purge(): @@ -34,6 +53,7 @@ def purge(): global processquantitynames_id global resourcequantitynames_enum global resourcequantitynames_id + global scheduleofrates_enum quantitytypes_enum = [] productquantitynames_enum = [] productquantitynames_count = [] @@ -41,12 +61,27 @@ def purge(): processquantitynames_id = 0 resourcequantitynames_enum = [] resourcequantitynames_id = 0 + scheduleofrates_enum = [] + + +def get_schedule_of_rates(self, context): + global scheduleofrates_enum + if len(scheduleofrates_enum) == 0: + scheduleofrates_enum.extend( + (str(ifc_definition_id), schedule["Name"] or "Unnamed", "") + for ifc_definition_id, schedule in Data.cost_schedules.items() + if schedule["PredefinedType"] == "SCHEDULEOFRATES" + ) + return scheduleofrates_enum + + +def update_schedule_of_rates(self, context): + bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(self.schedule_of_rates)) def getQuantityTypes(self, context): global quantitytypes_enum if len(quantitytypes_enum) == 0 and IfcStore.get_schema(): - quantitytypes_enum = [] quantitytypes_enum.extend( [ (t.name(), t.name(), "") @@ -125,7 +160,10 @@ def getResourceQuantityNames(self, context): def update_cost_item_index(self, context): - bpy.ops.bim.load_cost_item_quantities() + if Data.cost_schedules[self.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES": + bpy.ops.bim.load_cost_item_types() + else: + bpy.ops.bim.load_cost_item_quantities() def updateCostItemIdentification(self, context): @@ -175,6 +213,11 @@ class CostItemQuantity(PropertyGroup): total_quantity: FloatProperty(name="Total Quantity") +class CostItemType(PropertyGroup): + name: StringProperty(name="Name") + ifc_definition_id: IntProperty(name="IFC Definition ID") + + class BIMCostProperties(PropertyGroup): is_cost_update_enabled: BoolProperty(name="Is Cost Update Enabled", default=True) cost_schedule_attributes: CollectionProperty(name="Cost Schedule Attributes", type=Attribute) @@ -213,3 +256,11 @@ class BIMCostProperties(PropertyGroup): active_cost_item_process_index: IntProperty(name="Active Cost Item Process Index") cost_item_resources: CollectionProperty(name="Cost Item Resources", type=CostItemQuantity) active_cost_item_resource_index: IntProperty(name="Active Cost Item Resource Index") + cost_item_type_products: CollectionProperty(name="Cost Item Type Products", type=CostItemType) + active_cost_item_type_product_index: IntProperty(name="Active Cost Item Type Product Index") + schedule_of_rates: EnumProperty( + items=get_schedule_of_rates, name="Schedule Of Rates", update=update_schedule_of_rates + ) + cost_item_rates: CollectionProperty(name="Cost Item Rates", type=CostItem) + active_cost_item_rate_index: IntProperty(name="Active Cost Rate Index") + contracted_cost_item_rates: StringProperty(name="Contracted Cost Item Rates", default="[]") diff --git a/src/blenderbim/blenderbim/bim/module/cost/ui.py b/src/blenderbim/blenderbim/bim/module/cost/ui.py index 952dabd44d..12d5deaecc 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/ui.py +++ b/src/blenderbim/blenderbim/bim/module/cost/ui.py @@ -1,7 +1,27 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import blenderbim.bim.module.cost.prop as CostProp from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes from ifcopenshell.api.cost.data import Data +from ifcopenshell.api.unit.data import Data as UnitData class BIM_PT_cost_schedules(Panel): @@ -23,11 +43,19 @@ class BIM_PT_cost_schedules(Panel): if not Data.is_loaded: Data.load(IfcStore.get_file()) + if not UnitData.is_loaded: + UnitData.load(IfcStore.get_file()) + row = self.layout.row() row.operator("bim.add_cost_schedule", icon="ADD") - for cost_schedule_id, cost_schedule in Data.cost_schedules.items(): - self.draw_cost_schedule_ui(cost_schedule_id, cost_schedule) + if self.props.active_cost_schedule_id: + self.draw_cost_schedule_ui( + self.props.active_cost_schedule_id, Data.cost_schedules[self.props.active_cost_schedule_id] + ) + else: + for cost_schedule_id, cost_schedule in Data.cost_schedules.items(): + self.draw_cost_schedule_ui(cost_schedule_id, cost_schedule) def draw_cost_schedule_ui(self, cost_schedule_id, cost_schedule): row = self.layout.row(align=True) @@ -66,14 +94,7 @@ class BIM_PT_cost_schedules(Panel): self.layout.template_list("BIM_UL_cost_columns", "", self.props, "columns", self.props, "active_column_index") def draw_editable_cost_schedule_ui(self): - for attribute in self.props.cost_schedule_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.cost_schedule_attributes, self.layout) def draw_editable_cost_item_ui(self, cost_schedule_id): row = self.layout.row(align=True) @@ -119,18 +140,7 @@ class BIM_PT_cost_schedules(Panel): self.draw_editable_cost_item_values_ui() def draw_editable_cost_item_attributes_ui(self): - for attribute in self.props.cost_item_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.cost_item_attributes, self.layout) def draw_editable_cost_item_quantities_ui(self): row = self.layout.row(align=True) @@ -165,20 +175,7 @@ class BIM_PT_cost_schedules(Panel): self.draw_editable_cost_item_quantity_ui(box) def draw_editable_cost_item_quantity_ui(self, layout): - for attribute in self.props.quantity_attributes: - row = layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.quantity_attributes, self.layout) def draw_editable_cost_item_values_ui(self): row = self.layout.row(align=True) @@ -200,19 +197,20 @@ class BIM_PT_cost_schedules(Panel): self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_item_value_id]) def draw_readonly_cost_value_ui(self, layout, cost_value_id): + # This UI is really poor. Delete and start again. cost_value = Data.cost_values[cost_value_id] cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"]) if cost_value["Category"]: cost_value_label += " ({})".format(cost_value["Category"]) layout.label(text="", icon="DISC") - self.draw_cost_value_operator_ui(layout, cost_value_id) + self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_cost_item_id) layout.label(text=cost_value_label) for component_id in cost_value["Components"] or []: - self.draw_readonly_component_cost_value_ui(layout, component_id) + self.draw_readonly_component_cost_value_ui(layout, component_id, cost_value["id"]) - def draw_readonly_component_cost_value_ui(self, layout, cost_value_id, level=1): - self.draw_cost_value_operator_ui(layout, cost_value_id) + def draw_readonly_component_cost_value_ui(self, layout, cost_value_id, parent_id, level=1): + self.draw_cost_value_operator_ui(layout, cost_value_id, parent_id) cost_value = Data.cost_values[cost_value_id] cost_value_label = ">" * level cost_value_label += "{0:.2f}".format(cost_value["AppliedValue"]) @@ -221,9 +219,9 @@ class BIM_PT_cost_schedules(Panel): layout.label(text=cost_value_label) for component_id in cost_value["Components"] or []: - self.draw_readonly_component_cost_value_ui(layout, component_id, level + 1) + self.draw_readonly_component_cost_value_ui(layout, component_id, cost_value["id"], level + 1) - def draw_cost_value_operator_ui(self, layout, cost_value_id): + def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id): if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id: op = layout.operator("bim.edit_cost_value", text="", icon="CHECKMARK") op.cost_value = cost_value_id @@ -240,6 +238,7 @@ class BIM_PT_cost_schedules(Panel): if self.props.cost_types == "CATEGORY": op.cost_category = self.props.cost_category op = layout.operator("bim.remove_cost_item_value", text="", icon="X") + op.parent = parent_id op.cost_value = cost_value_id else: op = layout.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL") @@ -250,23 +249,97 @@ class BIM_PT_cost_schedules(Panel): if self.props.cost_types == "CATEGORY": op.cost_category = self.props.cost_category op = layout.operator("bim.remove_cost_item_value", text="", icon="X") + op.parent = parent_id op.cost_value = cost_value_id def draw_editable_cost_value_ui(self, layout, cost_value): - for attribute in self.props.cost_value_attributes: - row = layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.cost_value_attributes, layout) + + +class BIM_PT_cost_item_types(Panel): + bl_label = "IFC Cost Item Types" + bl_idname = "BIM_PT_cost_item_types" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_cost_schedules" + + @classmethod + def poll(cls, context): + props = context.scene.BIMCostProperties + total_cost_items = len(props.cost_items) + if not props.active_cost_schedule_id: + return False + if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES": + return False + if total_cost_items > 0 and props.active_cost_item_index < total_cost_items: + return True + return False + + def draw(self, context): + self.props = context.scene.BIMCostProperties + + cost_item = self.props.cost_items[self.props.active_cost_item_index] + + grid = self.layout.grid_flow(columns=3, even_columns=True) + + # Column1 + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Elements") + op = row2.operator("bim.assign_cost_item_type", text="", icon="ADD") + op.cost_item = cost_item.ifc_definition_id + op = row2.operator("bim.unassign_cost_item_type", text="", icon="REMOVE") + op.cost_item = cost_item.ifc_definition_id + op.related_object = 0 + op = row2.operator("bim.select_cost_item_products", icon="RESTRICT_SELECT_OFF", text="") + op.cost_item = cost_item.ifc_definition_id + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_types", + "", + self.props, + "cost_item_type_products", + self.props, + "active_cost_item_type_product_index", + ) + + # Column2 + # TODO + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Tasks") + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_quantities", + "", + self.props, + "cost_item_processes", + self.props, + "active_cost_item_process_index", + ) + + # Column3 + # TODO + col = grid.column() + + row2 = col.row(align=True) + row2.label(text="Resources") + + row2 = col.row() + row2.template_list( + "BIM_UL_cost_item_quantities", + "", + self.props, + "cost_item_resources", + self.props, + "active_cost_item_resource_index", + ) class BIM_PT_cost_item_quantities(Panel): @@ -282,6 +355,10 @@ class BIM_PT_cost_item_quantities(Panel): def poll(cls, context): props = context.scene.BIMCostProperties total_cost_items = len(props.cost_items) + if not props.active_cost_schedule_id: + return False + if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES": + return False if total_cost_items > 0 and props.active_cost_item_index < total_cost_items: return True return False @@ -371,26 +448,54 @@ class BIM_PT_cost_item_quantities(Panel): op.prop_name = self.props.resource_quantity_names -class BIM_UL_cost_items(UIList): +class BIM_PT_cost_item_rates(Panel): + bl_label = "IFC Cost Item Rates" + bl_idname = "BIM_PT_cost_item_rates" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_cost_schedules" + + @classmethod + def poll(cls, context): + props = context.scene.BIMCostProperties + total_cost_items = len(props.cost_items) + if not props.active_cost_schedule_id: + return False + if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES": + return False + if total_cost_items > 0 and props.active_cost_item_index < total_cost_items: + return True + return False + + def draw(self, context): + self.props = context.scene.BIMCostProperties + cost_item = self.props.cost_items[self.props.active_cost_item_index] + row = self.layout.row(align=True) + row.prop(self.props, "schedule_of_rates", text="") + if self.props.active_cost_item_rate_index < len(self.props.cost_item_rates): + op = row.operator("bim.assign_cost_value", text="", icon="COPYDOWN") + op.cost_item = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id + op.cost_rate = self.props.cost_item_rates[self.props.active_cost_item_rate_index].ifc_definition_id + self.layout.template_list( + "BIM_UL_cost_item_rates", + "", + self.props, + "cost_item_rates", + self.props, + "active_cost_item_rate_index", + ) + + +class BIM_UL_cost_items_trait: def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: self.props = context.scene.BIMCostProperties cost_item = Data.cost_items[item.ifc_definition_id] row = layout.row(align=True) - for i in range(0, item.level_index): - row.label(text="", icon="BLANK1") - if item.has_children: - if item.is_expanded: - row.operator( - "bim.contract_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" - ).cost_item = item.ifc_definition_id - else: - row.operator( - "bim.expand_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" - ).cost_item = item.ifc_definition_id - else: - row.label(text="", icon="DOT") + self.draw_hierarchy(row, item) split1 = row.split(factor=0.1) split1.prop(item, "identification", emboss=False, text="") @@ -398,24 +503,68 @@ class BIM_UL_cost_items(UIList): split2.alignment = "RIGHT" split2.prop(item, "name", emboss=False, text="") - if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES": - split2.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" ({cost_item['UnitSymbol'] or '?'})") - - split2.label(text="{0:.2f}".format(cost_item["TotalAppliedValue"])) + self.draw_quantity_column(split2, cost_item) + self.draw_value_column(split2, cost_item) for column in self.props.columns: split2.label(text=str(cost_item["CategoryValues"].get(column.name, "-"))) - split2.label(text="{0:.2f}".format(cost_item["TotalCostValue"])) - self.draw_buttons(split2, item, cost_item) + self.draw_total_cost_column(split2, cost_item) + # TODO: reimplement "bim.copy_cost_item_values" somewhere with better UX - def draw_buttons(self, row, item, cost_item): - pass # TODO: reimplement somewhere with better UX - # elif self.props.active_cost_item_id: - # if self.props.cost_item_editing_type == "VALUES": - # op = row.operator("bim.copy_cost_item_values", text="", icon="COPYDOWN") - # op.source = self.props.active_cost_item_id - # op.destination = item.ifc_definition_id + def draw_hierarchy(self, row, item): + for i in range(0, item.level_index): + row.label(text="", icon="BLANK1") + if item.has_children: + if item.is_expanded: + op = row.operator(self.contract_operator, text="", emboss=False, icon="DISCLOSURE_TRI_DOWN") + else: + op = row.operator(self.expand_operator, text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT") + op.cost_item = item.ifc_definition_id + else: + row.label(text="", icon="DOT") + + def draw_total_cost_column(self, layout, cost_item): + layout.label(text="{0:.2f}".format(cost_item["TotalCost"])) + + def draw_quantity_column(self, layout, cost_item): + if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES": + self.draw_uom_column(layout, cost_item) + else: + self.draw_total_quantity_column(layout, cost_item) + + def draw_value_column(self, layout, cost_item): + text = "{0:.2f}".format(cost_item["TotalAppliedValue"]) + if cost_item["UnitBasisValueComponent"] not in [None, 1]: + text += " / {}".format(round(cost_item["UnitBasisValueComponent"], 2)) + layout.label(text=text) + + def draw_uom_column(self, layout, cost_item): + layout.label(text=cost_item["UnitBasisUnitSymbol"] or "?" if cost_item["UnitBasisValueComponent"] else "-") + + def draw_total_quantity_column(self, layout, cost_item): + layout.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '?'}") + + +class BIM_UL_cost_items(BIM_UL_cost_items_trait, UIList): + def __init__(self): + self.contract_operator = "bim.contract_cost_item" + self.expand_operator = "bim.expand_cost_item" + + +class BIM_UL_cost_item_rates(BIM_UL_cost_items_trait, UIList): + # A schedule of rates UIList is identical to a regular cost items UIList but + # we want a separate UIList instance so that you can browse both lists + # independently in Blender. So we use a trait. + def __init__(self): + self.contract_operator = "bim.contract_cost_item_rate" + self.expand_operator = "bim.expand_cost_item_rate" + + def draw_quantity_column(self, layout, cost_item): + self.draw_uom_column(layout, cost_item) + + def draw_total_cost_column(self, layout, cost_item): + pass # No such thing as a total cost in a schedule of rates class BIM_UL_cost_columns(UIList): @@ -427,6 +576,19 @@ class BIM_UL_cost_columns(UIList): row.operator("bim.remove_cost_column", text="", icon="X").name = item.name +class BIM_UL_cost_item_types(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + props = context.scene.BIMCostProperties + cost_item = props.cost_items[props.active_cost_item_index] + + if item: + row = layout.row(align=True) + row.label(text=item.name) + op = row.operator("bim.unassign_cost_item_type", text="", icon="X") + op.cost_item = cost_item.ifc_definition_id + op.related_object = item.ifc_definition_id + + class BIM_UL_cost_item_quantities(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): props = context.scene.BIMCostProperties diff --git a/src/blenderbim/blenderbim/bim/module/covetool/__init__.py b/src/blenderbim/blenderbim/bim/module/covetool/__init__.py index 0113965696..837f9b8382 100644 --- a/src/blenderbim/blenderbim/bim/module/covetool/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/covetool/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/covetool/api.py b/src/blenderbim/blenderbim/bim/module/covetool/api.py index 50f39fdef4..d52e332b09 100644 --- a/src/blenderbim/blenderbim/bim/module/covetool/api.py +++ b/src/blenderbim/blenderbim/bim/module/covetool/api.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import requests diff --git a/src/blenderbim/blenderbim/bim/module/covetool/operator.py b/src/blenderbim/blenderbim/bim/module/covetool/operator.py index a1db49bdba..10820227c6 100644 --- a/src/blenderbim/blenderbim/bim/module/covetool/operator.py +++ b/src/blenderbim/blenderbim/bim/module/covetool/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/covetool/prop.py b/src/blenderbim/blenderbim/bim/module/covetool/prop.py index 122d6b1cb1..018cac6566 100644 --- a/src/blenderbim/blenderbim/bim/module/covetool/prop.py +++ b/src/blenderbim/blenderbim/bim/module/covetool/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy.props import bpy.types diff --git a/src/blenderbim/blenderbim/bim/module/covetool/ui.py b/src/blenderbim/blenderbim/bim/module/covetool/ui.py index 70b35ef6c0..d5a91d578c 100644 --- a/src/blenderbim/blenderbim/bim/module/covetool/ui.py +++ b/src/blenderbim/blenderbim/bim/module/covetool/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy.types diff --git a/src/blenderbim/blenderbim/bim/module/csv/__init__.py b/src/blenderbim/blenderbim/bim/module/csv/__init__.py index 3e0e3722b9..24722c9420 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/csv/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/csv/operator.py b/src/blenderbim/blenderbim/bim/module/csv/operator.py index 8618de15ca..e9f9c0739c 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/operator.py +++ b/src/blenderbim/blenderbim/bim/module/csv/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifccsv import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/csv/prop.py b/src/blenderbim/blenderbim/bim/module/csv/prop.py index a21893cc94..f1e0dc93f0 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/prop.py +++ b/src/blenderbim/blenderbim/bim/module/csv/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/csv/ui.py b/src/blenderbim/blenderbim/bim/module/csv/ui.py index 025dfc7396..347877f616 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/ui.py +++ b/src/blenderbim/blenderbim/bim/module/csv/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/debug/__init__.py b/src/blenderbim/blenderbim/bim/module/debug/__init__.py index b5d7474567..9406090275 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/debug/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/debug/operator.py b/src/blenderbim/blenderbim/bim/module/debug/operator.py index bcb196c9b4..7ef5b31b99 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/operator.py +++ b/src/blenderbim/blenderbim/bim/module/debug/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import logging import ifcopenshell @@ -146,7 +165,7 @@ class SelectHighPolygonMeshes(bpy.types.Operator): def execute(self, context): [o.select_set(True) for o in context.view_layer.objects - if o.type == 'MESH' + if o.type == "MESH" and len(o.data.polygons) > context.scene.BIMDebugProperties.number_of_polygons] return {"FINISHED"} @@ -178,18 +197,16 @@ class InspectFromStepId(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() - context.scene.BIMDebugProperties.active_step_id = self.step_id + debug_props = context.scene.BIMDebugProperties + debug_props.active_step_id = self.step_id crumb = context.scene.BIMDebugProperties.step_id_breadcrumb.add() crumb.name = str(self.step_id) element = self.file.by_id(self.step_id) - while len(context.scene.BIMDebugProperties.attributes) > 0: - context.scene.BIMDebugProperties.attributes.remove(0) - while len(context.scene.BIMDebugProperties.inverse_attributes) > 0: - context.scene.BIMDebugProperties.inverse_attributes.remove(0) - while len(context.scene.BIMDebugProperties.inverse_references) > 0: - context.scene.BIMDebugProperties.inverse_references.remove(0) + debug_props.attributes.clear() + debug_props.inverse_attributes.clear() + debug_props.inverse_references.clear() for key, value in element.get_info().items(): - self.add_attribute(context.scene.BIMDebugProperties.attributes, key, value) + self.add_attribute(debug_props.attributes, key, value) for key in dir(element): if ( not key[0].isalpha() @@ -198,9 +215,9 @@ class InspectFromStepId(bpy.types.Operator): or not getattr(element, key) ): continue - self.add_attribute(context.scene.BIMDebugProperties.inverse_attributes, key, getattr(element, key)) + self.add_attribute(debug_props.inverse_attributes, key, getattr(element, key)) for inverse in self.file.get_inverse(element): - new = context.scene.BIMDebugProperties.inverse_references.add() + new = debug_props.inverse_references.add() new.string_value = str(inverse) new.int_value = inverse.id() return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/debug/prop.py b/src/blenderbim/blenderbim/bim/module/debug/prop.py index d7b6868eeb..49369f4ff0 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/prop.py +++ b/src/blenderbim/blenderbim/bim/module/debug/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup from bpy.props import ( diff --git a/src/blenderbim/blenderbim/bim/module/debug/ui.py b/src/blenderbim/blenderbim/bim/module/debug/ui.py index 7575fa4f7b..68ce199db7 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/ui.py +++ b/src/blenderbim/blenderbim/bim/module/debug/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel diff --git a/src/blenderbim/blenderbim/bim/module/diff/__init__.py b/src/blenderbim/blenderbim/bim/module/diff/__init__.py index 6c551c11ce..a296d69a9e 100644 --- a/src/blenderbim/blenderbim/bim/module/diff/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/diff/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/diff/operator.py b/src/blenderbim/blenderbim/bim/module/diff/operator.py index 6054df59b8..8befc8e1c2 100644 --- a/src/blenderbim/blenderbim/bim/module/diff/operator.py +++ b/src/blenderbim/blenderbim/bim/module/diff/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifccsv import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/diff/prop.py b/src/blenderbim/blenderbim/bim/module/diff/prop.py index 3de92192a7..6233a02a9a 100644 --- a/src/blenderbim/blenderbim/bim/module/diff/prop.py +++ b/src/blenderbim/blenderbim/bim/module/diff/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/diff/ui.py b/src/blenderbim/blenderbim/bim/module/diff/ui.py index 692b79d37e..9cfbd3efde 100644 --- a/src/blenderbim/blenderbim/bim/module/diff/ui.py +++ b/src/blenderbim/blenderbim/bim/module/diff/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/document/__init__.py b/src/blenderbim/blenderbim/bim/module/document/__init__.py index cd2ef94e5d..6d1a6ab13e 100644 --- a/src/blenderbim/blenderbim/bim/module/document/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/document/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/document/operator.py b/src/blenderbim/blenderbim/bim/module/document/operator.py index 906fbb97e5..1d9ed2929d 100644 --- a/src/blenderbim/blenderbim/bim/module/document/operator.py +++ b/src/blenderbim/blenderbim/bim/module/document/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -14,8 +33,7 @@ class LoadInformation(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMDocumentProperties - while len(props.documents) > 0: - props.documents.remove(0) + props.documents.clear() for information_id, information in Data.information.items(): new = props.documents.add() new.name = information["Name"] or "Unnamed" @@ -37,8 +55,7 @@ class LoadDocumentReferences(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMDocumentProperties - while len(props.documents) > 0: - props.documents.remove(0) + props.documents.clear() for reference_id, reference in Data.references.items(): new = props.documents.add() new.name = reference["Name"] or "Unnamed" @@ -71,8 +88,7 @@ class EnableEditingDocument(bpy.types.Operator): def execute(self, context): props = context.scene.BIMDocumentProperties - while len(props.document_attributes) > 0: - props.document_attributes.remove(0) + props.document_attributes.clear() if props.is_editing == "information": data = Data.information[self.document] diff --git a/src/blenderbim/blenderbim/bim/module/document/prop.py b/src/blenderbim/blenderbim/bim/module/document/prop.py index 2208551acf..e93fc291d9 100644 --- a/src/blenderbim/blenderbim/bim/module/document/prop.py +++ b/src/blenderbim/blenderbim/bim/module/document/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/document/ui.py b/src/blenderbim/blenderbim/bim/module/document/ui.py index 0bbafafb77..e13e2fcb95 100644 --- a/src/blenderbim/blenderbim/bim/module/document/ui.py +++ b/src/blenderbim/blenderbim/bim/module/document/ui.py @@ -1,5 +1,25 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes from ifcopenshell.api.document.data import Data @@ -26,7 +46,7 @@ class BIM_PT_documents(Panel): row.label(text="{} Documents Found".format(len(Data.information)), icon="FILE") if self.props.is_editing == "information": row.operator("bim.add_information", text="", icon="ADD") - row.operator("bim.disable_document_editing_ui", text="", icon="X") + row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL") else: row.operator("bim.load_information", text="", icon="IMPORT") @@ -35,7 +55,7 @@ class BIM_PT_documents(Panel): row.label(text="{} References Found".format(len(Data.references)), icon="FILE_HIDDEN") if self.props.is_editing == "reference": row.operator("bim.add_document_reference", text="", icon="ADD") - row.operator("bim.disable_document_editing_ui", text="", icon="X") + row.operator("bim.disable_document_editing_ui", text="", icon="CANCEL") else: row.operator("bim.load_document_references", text="", icon="IMPORT") @@ -48,14 +68,7 @@ class BIM_PT_documents(Panel): self.draw_editable_ui(context) def draw_editable_ui(self, context): - for attribute in self.props.document_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.document_attributes, self.layout) class BIM_PT_object_documents(Panel): @@ -116,7 +129,7 @@ class BIM_PT_object_documents(Panel): row = self.layout.row(align=True) icon = "FILE" if self.props.is_adding == "IfcDocumentInformation" else "FILE_HIDDEN" row.label(text="Adding {}".format(self.props.is_adding), icon=icon) - row.operator("bim.disable_assigning_document", text="", icon="X") + row.operator("bim.disable_assigning_document", text="", icon="CANCEL") self.layout.template_list( "BIM_UL_object_documents", "", @@ -142,7 +155,7 @@ class BIM_UL_documents(UIList): row.operator("bim.edit_information", text="", icon="CHECKMARK") elif context.scene.BIMDocumentProperties.is_editing == "reference": row.operator("bim.edit_document_reference", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_document", text="", icon="X") + row.operator("bim.disable_editing_document", text="", icon="CANCEL") elif context.scene.BIMDocumentProperties.active_document_id: row.operator("bim.remove_document", text="", icon="X").document = item.ifc_definition_id else: diff --git a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py index e289ea4aa1..a100f5fc1a 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator, handler, gizmos diff --git a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py index d2dd4b0f7d..8eaffe09f8 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/annotation.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import os from mathutils import Vector diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index ac36c8506c..219d52c3fb 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + """Viewport decorations""" import math from functools import reduce diff --git a/src/blenderbim/blenderbim/bim/module/drawing/gizmos.py b/src/blenderbim/blenderbim/bim/module/drawing/gizmos.py index 65fbe7e339..3f8965fe14 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/gizmos.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/gizmos.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import blf import math diff --git a/src/blenderbim/blenderbim/bim/module/drawing/handler.py b/src/blenderbim/blenderbim/bim/module/drawing/handler.py index ef581c6d78..1c6fff0512 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/handler.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/handler.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import blenderbim.bim.module.drawing.decoration as decoration from bpy.app.handlers import persistent diff --git a/src/blenderbim/blenderbim/bim/module/drawing/helper.py b/src/blenderbim/blenderbim/bim/module/drawing/helper.py index 6285251c4d..e7a1c9ad19 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/helper.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/helper.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import math import mathutils.geometry @@ -244,7 +263,7 @@ def get_active_drawing(scene): if props.active_drawing_index is None or len(props.drawings) == 0: return None, None try: - drawing = props.drawings[props.active_drawing_index] + drawing = props.active_drawing return scene.collection.children["Views"].children[f"IfcGroup/{drawing.name}"], drawing.camera except (KeyError, IndexError): raise RuntimeError("missing drawing collection") diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 54181dff45..d78db7b340 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import re import bpy @@ -12,11 +31,13 @@ import ifcopenshell import ifcopenshell.geom import ifcopenshell.util.selector import ifcopenshell.util.representation +import blenderbim.bim.schema import blenderbim.bim.module.drawing.svgwriter as svgwriter import blenderbim.bim.module.drawing.annotation as annotation import blenderbim.bim.module.drawing.sheeter as sheeter import blenderbim.bim.module.drawing.scheduler as scheduler import blenderbim.bim.module.drawing.helper as helper +from blenderbim.bim.module.drawing.prop import RasterStyleProperty from mathutils import Vector, Matrix, Euler, geometry from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data as GroupData @@ -39,6 +60,10 @@ class AddDrawing(bpy.types.Operator): bl_label = "Add Drawing" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): return IfcStore.execute_ifc_operator(self, context) @@ -72,34 +97,52 @@ class AddDrawing(bpy.types.Operator): group = self.file.by_id(sorted(GroupData.groups.keys())[-1]) ifcopenshell.api.run("group.edit_group", self.file, **{"group": group, "attributes": {"Name": new.name}}) bpy.ops.bim.assign_group(product=camera.name, group=group.id()) - bpy.ops.bim.add_pset(obj=camera.name, obj_type="Object", pset_name="EPset_Drawing") - pset_id = sorted(PsetData.products[camera.BIMObjectProperties.ifc_definition_id]["psets"])[-1] - bpy.ops.bim.edit_pset( - obj=camera.name, - obj_type="Object", - pset_id=pset_id, - properties=json.dumps({"TargetView": "PLAN_VIEW", "Scale": "1/100"}), + pset = ifcopenshell.api.run( + "pset.add_pset", + self.file, + **{ + "product": self.file.by_id(camera.BIMObjectProperties.ifc_definition_id), + "name": "EPset_Drawing", + }, ) + ifcopenshell.api.run( + "pset.edit_pset", + self.file, + **{ + "pset": pset, + "properties": {"TargetView": "PLAN_VIEW", "Scale": "1/100"}, + "pset_template": blenderbim.bim.schema.ifc.psetqto.get_by_name("EPset_Drawing"), + }, + ) + PsetData.load(IfcStore.get_file(), camera.BIMObjectProperties.ifc_definition_id) return {"FINISHED"} class CreateDrawing(bpy.types.Operator): + """Creates a svg drawing + + Only available if : + - IFC file is created + - Camera is in Orthographic mode + """ bl_idname = "bim.create_drawing" bl_label = "Create Drawing" + @classmethod + def poll(cls, context): + camera = context.scene.camera + return IfcStore.get_file() \ + and camera.type == "CAMERA" and camera.data.type == "ORTHO" \ + and camera.BIMObjectProperties.ifc_definition_id + def execute(self, context): self.camera = context.scene.camera - if ( - not (self.camera.type == "CAMERA" and self.camera.data.type == "ORTHO") - or not self.camera.BIMObjectProperties.ifc_definition_id - ): - return self.file = IfcStore.get_file() self.time = None start = time.time() self.profile_code("Start drawing generation process") self.props = context.scene.DocProperties - self.drawing_name = IfcStore.get_file().by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name + self.drawing_name = self.file.by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name underlay_svg = self.generate_underlay(context) self.profile_code("Generate underlay") linework_svg = self.generate_linework(context) @@ -108,7 +151,7 @@ class CreateDrawing(bpy.types.Operator): self.profile_code("Generate annotation") svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg) self.profile_code("Combine SVG layers") - open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.svg_command, svg_path) + open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg_path) print("Total Time: {:.2f}".format(time.time() - start)) return {"FINISHED"} @@ -166,8 +209,8 @@ class CreateDrawing(bpy.types.Operator): if not self.props.has_underlay: return svg_path = os.path.join(context.scene.BIMProperties.data_dir, "cache", self.drawing_name + "-underlay.svg") - bpy.context.scene.render.filepath = svg_path[0:-4] + ".png" - drawing_style = bpy.context.scene.DocProperties.drawing_styles[ + context.scene.render.filepath = svg_path[0:-4] + ".png" + drawing_style = context.scene.DocProperties.drawing_styles[ self.camera.data.BIMCameraProperties.active_drawing_style_index ] @@ -178,7 +221,7 @@ class CreateDrawing(bpy.types.Operator): for obj in self.camera.users_collection[0].objects: previous_visibility[obj.name] = obj.hide_get() obj.hide_set(True) - for obj in bpy.context.visible_objects: + for obj in context.visible_objects: if ( (not obj.data and not obj.instance_collection) or isinstance(obj.data, bpy.types.Camera) @@ -189,14 +232,14 @@ class CreateDrawing(bpy.types.Operator): previous_visibility[obj.name] = obj.hide_get() obj.hide_set(True) - space = self.get_view_3d() + space = self.get_view_3d(context.screen.areas) previous_shading = space.shading.type - previous_format = bpy.context.scene.render.image_settings.file_format + previous_format = context.scene.render.image_settings.file_format space.shading.type = "RENDERED" - bpy.context.scene.render.image_settings.file_format = "PNG" + context.scene.render.image_settings.file_format = "PNG" bpy.ops.render.opengl(write_still=True) space.shading.type = previous_shading - bpy.context.scene.render.image_settings.file_format = previous_format + context.scene.render.image_settings.file_format = previous_format for name, value in previous_visibility.items(): bpy.data.objects[name].hide_set(value) @@ -210,7 +253,7 @@ class CreateDrawing(bpy.types.Operator): svg_writer.human_scale = "NTS" else: svg_writer.human_scale = human_scale - render = bpy.context.scene.render + render = context.scene.render if self.is_landscape(): width = self.camera.data.ortho_scale height = width / render.resolution_x * render.resolution_y @@ -218,13 +261,13 @@ class CreateDrawing(bpy.types.Operator): height = self.camera.data.ortho_scale width = height / render.resolution_y * render.resolution_x svg_writer.output = svg_path - svg_writer.data_dir = bpy.context.scene.BIMProperties.data_dir + svg_writer.data_dir = context.scene.BIMProperties.data_dir svg_writer.vector_style = drawing_style.vector_style svg_writer.camera = self.camera svg_writer.camera_width = width svg_writer.camera_height = height svg_writer.camera_projection = tuple(self.camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))) - svg_writer.background_image = bpy.context.scene.render.filepath + svg_writer.background_image = context.scene.render.filepath svg_writer.write("underlay") return svg_path @@ -313,12 +356,12 @@ class CreateDrawing(bpy.types.Operator): else: svg_writer.human_scale = human_scale - drawing_style = bpy.context.scene.DocProperties.drawing_styles[ + drawing_style = context.scene.DocProperties.drawing_styles[ camera.data.BIMCameraProperties.active_drawing_style_index ] - render = bpy.context.scene.render - if self.is_landscape(): + render = context.scene.render + if self.is_landscape(render): width = camera.data.ortho_scale height = width / render.resolution_x * render.resolution_y else: @@ -327,7 +370,7 @@ class CreateDrawing(bpy.types.Operator): svg_writer.scale = float(numerator) / float(denominator) svg_writer.output = svg_path - svg_writer.data_dir = bpy.context.scene.BIMProperties.data_dir + svg_writer.data_dir = context.scene.BIMProperties.data_dir svg_writer.vector_style = drawing_style.vector_style svg_writer.camera = camera svg_writer.camera_width = width @@ -372,11 +415,11 @@ class CreateDrawing(bpy.types.Operator): svg_writer.write("annotation") return svg_writer.output - def is_landscape(self): - return bpy.context.scene.render.resolution_x > bpy.context.scene.render.resolution_y + def is_landscape(self, render): + return render.resolution_x > render.resolution_y - def get_view_3d(self): - for area in bpy.context.screen.areas: + def get_view_3d(self, areas): + for area in areas: if area.type != "VIEW_3D": continue for space in area.spaces: @@ -463,12 +506,14 @@ class AddAnnotation(bpy.types.Operator): obj_name: bpy.props.StringProperty() data_type: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + return IfcStore.get_file() and context.scene.camera + def execute(self, context): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - if not context.scene.camera: - return {"FINISHED"} subcontext = ifcopenshell.util.representation.get_context( IfcStore.get_file(), "Plan", "Annotation", context.scene.camera.data.BIMCameraProperties.target_view ) @@ -493,7 +538,7 @@ class AddAnnotation(bpy.types.Operator): bpy.ops.bim.update_representation(obj=obj.name) bpy.ops.object.select_all(action="DESELECT") - bpy.context.view_layer.objects.active = obj + context.view_layer.objects.active = obj obj.select_set(True) bpy.ops.object.mode_set(mode="EDIT") return {"FINISHED"} @@ -506,11 +551,12 @@ class AddSheet(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - new = bpy.context.scene.DocProperties.sheets.add() - new.name = "{} - SHEET".format(len(bpy.context.scene.DocProperties.sheets)) + scene = context.scene + new = scene.DocProperties.sheets.add() + new.name = "{} - SHEET".format(len(scene.DocProperties.sheets)) sheet_builder = sheeter.SheetBuilder() - sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir - sheet_builder.create(new.name, bpy.context.scene.DocProperties.titleblock) + sheet_builder.data_dir = scene.BIMProperties.data_dir + sheet_builder.create(new.name, scene.DocProperties.titleblock) return {"FINISHED"} @@ -519,11 +565,11 @@ class OpenSheet(bpy.types.Operator): bl_label = "Open Sheet" def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties open_with_user_command( - bpy.context.preferences.addons["blenderbim"].preferences.svg_command, + context.preferences.addons["blenderbim"].preferences.svg_command, os.path.join( - bpy.context.scene.BIMProperties.data_dir, "sheets", props.sheets[props.active_sheet_index].name + ".svg" + context.scene.BIMProperties.data_dir, "sheets", props.active_sheet.name + ".svg" ), ) return {"FINISHED"} @@ -536,14 +582,14 @@ class AddDrawingToSheet(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties sheet_builder = sheeter.SheetBuilder() - sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir + sheet_builder.data_dir = context.scene.BIMProperties.data_dir try: sheet_builder.add_drawing( - props.drawings[props.active_drawing_index].name, props.sheets[props.active_sheet_index].name + props.drawings.active_drawing.name, props.active_sheet.name ) - except: + except FileNotFoundError: self.report({"ERROR"}, "Drawings need to be created before being added to a sheet") return {"FINISHED"} @@ -554,17 +600,18 @@ class CreateSheets(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - props = bpy.context.scene.DocProperties - name = props.sheets[props.active_sheet_index].name + scene = context.scene + props = scene.DocProperties + name = props.active_sheet.name sheet_builder = sheeter.SheetBuilder() - sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir + sheet_builder.data_dir = scene.BIMProperties.data_dir sheet_builder.build(name) - svg2pdf_command = bpy.context.preferences.addons["blenderbim"].preferences.svg2pdf_command - svg2dxf_command = bpy.context.preferences.addons["blenderbim"].preferences.svg2dxf_command + svg2pdf_command = context.preferences.addons["blenderbim"].preferences.svg2pdf_command + svg2dxf_command = context.preferences.addons["blenderbim"].preferences.svg2dxf_command if svg2pdf_command: - path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "build", name) + path = os.path.join(scene.BIMProperties.data_dir, "build", name) svg = os.path.join(path, name + ".svg") pdf = os.path.join(path, name + ".pdf") # With great power comes great responsibility. Example: @@ -574,7 +621,7 @@ class CreateSheets(bpy.types.Operator): subprocess.run(command) if svg2dxf_command: - path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "build", name) + path = os.path.join(scene.BIMProperties.data_dir, "build", name) svg = os.path.join(path, name + ".svg") eps = os.path.join(path, name + ".eps") dxf = os.path.join(path, name + ".dxf") @@ -586,11 +633,11 @@ class CreateSheets(bpy.types.Operator): subprocess.run(command) if svg2pdf_command: - open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.pdf_command, pdf) + open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf) else: open_with_user_command( - bpy.context.preferences.addons["blenderbim"].preferences.svg_command, - os.path.join(bpy.context.scene.BIMProperties.data_dir, "build", name, name + ".svg"), + context.preferences.addons["blenderbim"].preferences.svg_command, + os.path.join(scene.BIMProperties.data_dir, "build", name, name + ".svg"), ) return {"FINISHED"} @@ -602,26 +649,31 @@ class OpenView(bpy.types.Operator): def execute(self, context): open_with_user_command( - bpy.context.preferences.addons["blenderbim"].preferences.svg_command, - os.path.join(bpy.context.scene.BIMProperties.data_dir, "diagrams", self.view + ".svg"), + context.preferences.addons["blenderbim"].preferences.svg_command, + os.path.join(context.scene.BIMProperties.data_dir, "diagrams", self.view + ".svg"), ) return {"FINISHED"} class OpenViewCamera(bpy.types.Operator): + """Select this drawing's camera object and expand its drawing properties""" bl_idname = "bim.open_view_camera" bl_label = "Open View Camera" bl_options = {"REGISTER", "UNDO"} view_name: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + return bpy.context.object.mode == "OBJECT" + 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 + doc_props = context.scene.DocProperties + doc_props.active_drawing_index = doc_props.drawings.find(self.view_name) + drawing = doc_props.active_drawing bpy.ops.object.select_all(action="DESELECT") drawing.camera.select_set(True) - for area in bpy.context.screen.areas: + context.view_layer.objects.active = drawing.camera + for area in context.screen.areas: if area.ui_type == "PROPERTIES": for space in area.spaces: space.context = "DATA" @@ -635,22 +687,22 @@ class ActivateView(bpy.types.Operator): drawing_index: bpy.props.IntProperty() def execute(self, context): - camera = bpy.context.scene.DocProperties.drawings[self.drawing_index].camera + camera = context.scene.DocProperties.drawings[self.drawing_index].camera if not camera: return {"FINISHED"} - area = next(area for area in bpy.context.screen.areas if area.type == "VIEW_3D") + area = next(area for area in context.screen.areas if area.type == "VIEW_3D") is_local_view = area.spaces[0].local_view is not None if is_local_view: bpy.ops.view3d.localview() - bpy.context.scene.camera = camera + context.scene.camera = camera bpy.ops.view3d.localview() else: - bpy.context.scene.camera = camera + context.scene.camera = camera area.spaces[0].region_3d.view_perspective = "CAMERA" views_collection = bpy.data.collections.get("Views") for collection in views_collection.children: # We assume the project collection is at the top level - for project_collection in bpy.context.view_layer.layer_collection.children: + for project_collection in context.view_layer.layer_collection.children: # We assume a convention that the 'Views' collection is directly # in the project collection if ( @@ -659,7 +711,7 @@ class ActivateView(bpy.types.Operator): ): project_collection.children["Views"].children[collection.name].hide_viewport = True bpy.data.collections.get(collection.name).hide_render = True - bpy.context.view_layer.layer_collection.children["Views"].children[ + context.view_layer.layer_collection.children["Views"].children[ camera.users_collection[0].name ].hide_viewport = False bpy.data.collections.get(camera.users_collection[0].name).hide_render = False @@ -671,11 +723,12 @@ class SelectDocIfcFile(bpy.types.Operator): bl_idname = "bim.select_doc_ifc_file" bl_label = "Select Documentation IFC File" bl_options = {"REGISTER", "UNDO"} + filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) filepath: bpy.props.StringProperty(subtype="FILE_PATH") index: bpy.props.IntProperty() def execute(self, context): - bpy.context.scene.DocProperties.ifc_files[self.index].name = self.filepath + context.scene.DocProperties.ifc_files[self.index].name = self.filepath return {"FINISHED"} def invoke(self, context, event): @@ -689,7 +742,7 @@ class GenerateReferences(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - self.camera = bpy.context.scene.camera + self.camera = context.scene.camera self.filter_potential_references() if self.camera.data.BIMCameraProperties.target_view == "PLAN_VIEW": self.generate_grids() @@ -758,7 +811,7 @@ class ResizeText(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - for obj in bpy.context.scene.camera.users_collection[0].objects: + for obj in context.scene.camera.users_collection[0].objects: if isinstance(obj.data, bpy.types.TextCurve): annotation.Annotator.resize_text(obj) return {"FINISHED"} @@ -770,7 +823,7 @@ class AddVariable(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - bpy.context.active_object.data.BIMTextProperties.variables.add() + context.active_object.data.BIMTextProperties.variables.add() return {"FINISHED"} @@ -781,7 +834,7 @@ class RemoveVariable(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - bpy.context.active_object.data.BIMTextProperties.variables.remove(self.index) + context.active_object.data.BIMTextProperties.variables.remove(self.index) return {"FINISHED"} @@ -791,8 +844,8 @@ class PropagateTextData(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - source = bpy.context.active_object - for obj in bpy.context.selected_objects: + source = context.active_object + for obj in context.selected_objects: if obj == source: continue obj.data.body = source.data.body @@ -800,8 +853,7 @@ class PropagateTextData(bpy.types.Operator): obj.data.align_y = source.data.align_y obj.data.BIMTextProperties.font_size = source.data.BIMTextProperties.font_size obj.data.BIMTextProperties.symbol = source.data.BIMTextProperties.symbol - while len(obj.data.BIMTextProperties.variables) > 0: - obj.data.BIMTextProperties.variables.remove(0) + obj.data.BIMTextProperties.variables.clear() for variable in source.data.BIMTextProperties.variables: new_variable = obj.data.BIMTextProperties.variables.add() new_variable.name = variable.name @@ -816,7 +868,7 @@ class RemoveDrawing(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties camera = props.drawings[self.index].camera collection = camera.users_collection[0] for obj in collection.objects: @@ -832,7 +884,7 @@ class AddDrawingStyle(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - new = bpy.context.scene.DocProperties.drawing_styles.add() + new = context.scene.DocProperties.drawing_styles.add() new.name = "New Drawing Style" return {"FINISHED"} @@ -844,7 +896,7 @@ class RemoveDrawingStyle(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - bpy.context.scene.DocProperties.drawing_styles.remove(self.index) + context.scene.DocProperties.drawing_styles.remove(self.index) return {"FINISHED"} @@ -856,42 +908,26 @@ class SaveDrawingStyle(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - space = self.get_view_3d() - style = { - "bpy.data.worlds[0].color": tuple(bpy.data.worlds[0].color), - "bpy.context.scene.render.engine": bpy.context.scene.render.engine, - "bpy.context.scene.render.film_transparent": bpy.context.scene.render.film_transparent, - "bpy.context.scene.display.shading.show_object_outline": bpy.context.scene.display.shading.show_object_outline, - "bpy.context.scene.display.shading.show_cavity": bpy.context.scene.display.shading.show_cavity, - "bpy.context.scene.display.shading.cavity_type": bpy.context.scene.display.shading.cavity_type, - "bpy.context.scene.display.shading.curvature_ridge_factor": bpy.context.scene.display.shading.curvature_ridge_factor, - "bpy.context.scene.display.shading.curvature_valley_factor": bpy.context.scene.display.shading.curvature_valley_factor, - "bpy.context.scene.view_settings.view_transform": bpy.context.scene.view_settings.view_transform, - "bpy.context.scene.display.shading.light": bpy.context.scene.display.shading.light, - "bpy.context.scene.display.shading.color_type": bpy.context.scene.display.shading.color_type, - "bpy.context.scene.display.shading.single_color": tuple(bpy.context.scene.display.shading.single_color), - "bpy.context.scene.display.shading.show_shadows": bpy.context.scene.display.shading.show_shadows, - "bpy.context.scene.display.shading.shadow_intensity": bpy.context.scene.display.shading.shadow_intensity, - "bpy.context.scene.display.light_direction": tuple(bpy.context.scene.display.light_direction), - "bpy.context.scene.view_settings.use_curve_mapping": bpy.context.scene.view_settings.use_curve_mapping, - "space.overlay.show_wireframes": space.overlay.show_wireframes, - "space.overlay.wireframe_threshold": space.overlay.wireframe_threshold, - "space.overlay.show_floor": space.overlay.show_floor, - "space.overlay.show_axis_x": space.overlay.show_axis_x, - "space.overlay.show_axis_y": space.overlay.show_axis_y, - "space.overlay.show_axis_z": space.overlay.show_axis_z, - "space.overlay.show_object_origins": space.overlay.show_object_origins, - "space.overlay.show_relationship_lines": space.overlay.show_relationship_lines, - } + space = self.get_view_3d(context) # Do not remove. It is used later in eval + scene = context.scene + style = {} + for prop in RasterStyleProperty: + value = eval(prop.value) + if not isinstance(value, str): + try: + value = tuple(value) + except TypeError: + pass + style[prop.value] = value if self.index: index = int(self.index) else: - index = bpy.context.active_object.data.BIMCameraProperties.active_drawing_style_index - bpy.context.scene.DocProperties.drawing_styles[index].raster_style = json.dumps(style) + index = context.active_object.data.BIMCameraProperties.active_drawing_style_index + scene.DocProperties.drawing_styles[index].raster_style = json.dumps(style) return {"FINISHED"} - def get_view_3d(self): - for area in bpy.context.screen.areas: + def get_view_3d(self, context): + for area in context.screen.areas: if area.type != "VIEW_3D": continue for space in area.spaces: @@ -906,56 +942,32 @@ class ActivateDrawingStyle(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - if context.scene.camera.data.BIMCameraProperties.active_drawing_style_index < len( - bpy.context.scene.DocProperties.drawing_styles + scene = context.scene + if scene.camera.data.BIMCameraProperties.active_drawing_style_index < len( + scene.DocProperties.drawing_styles ): - self.drawing_style = bpy.context.scene.DocProperties.drawing_styles[ - context.scene.camera.data.BIMCameraProperties.active_drawing_style_index + self.drawing_style = scene.DocProperties.drawing_styles[ + scene.camera.data.BIMCameraProperties.active_drawing_style_index ] - self.set_raster_style() - self.set_query() + self.set_raster_style(context) + self.set_query(context) return {"FINISHED"} - def set_raster_style(self): - space = self.get_view_3d() + def set_raster_style(self, context): + scene = context.scene # Do not remove. It is used in exec later + space = self.get_view_3d(context) # Do not remove. It is used in exec later style = json.loads(self.drawing_style.raster_style) - bpy.data.worlds[0].color = style["bpy.data.worlds[0].color"] - bpy.context.scene.render.engine = style["bpy.context.scene.render.engine"] - bpy.context.scene.render.film_transparent = style["bpy.context.scene.render.film_transparent"] - bpy.context.scene.display.shading.show_object_outline = style[ - "bpy.context.scene.display.shading.show_object_outline" - ] - bpy.context.scene.display.shading.show_cavity = style["bpy.context.scene.display.shading.show_cavity"] - bpy.context.scene.display.shading.cavity_type = style["bpy.context.scene.display.shading.cavity_type"] - bpy.context.scene.display.shading.curvature_ridge_factor = style[ - "bpy.context.scene.display.shading.curvature_ridge_factor" - ] - bpy.context.scene.display.shading.curvature_valley_factor = style[ - "bpy.context.scene.display.shading.curvature_valley_factor" - ] - bpy.context.scene.view_settings.view_transform = style["bpy.context.scene.view_settings.view_transform"] - bpy.context.scene.display.shading.light = style["bpy.context.scene.display.shading.light"] - bpy.context.scene.display.shading.color_type = style["bpy.context.scene.display.shading.color_type"] - bpy.context.scene.display.shading.single_color = style["bpy.context.scene.display.shading.single_color"] - bpy.context.scene.display.shading.show_shadows = style["bpy.context.scene.display.shading.show_shadows"] - bpy.context.scene.display.shading.shadow_intensity = style["bpy.context.scene.display.shading.shadow_intensity"] - bpy.context.scene.display.light_direction = style["bpy.context.scene.display.light_direction"] + for path, value in style.items(): + if isinstance(value, str): + exec(f"{path} = '{value}'") + else: + exec(f"{path} = {value}") - bpy.context.scene.view_settings.use_curve_mapping = style["bpy.context.scene.view_settings.use_curve_mapping"] - space.overlay.show_wireframes = style["space.overlay.show_wireframes"] - space.overlay.wireframe_threshold = style["space.overlay.wireframe_threshold"] - space.overlay.show_floor = style["space.overlay.show_floor"] - space.overlay.show_axis_x = style["space.overlay.show_axis_x"] - space.overlay.show_axis_y = style["space.overlay.show_axis_y"] - space.overlay.show_axis_z = style["space.overlay.show_axis_z"] - space.overlay.show_object_origins = style["space.overlay.show_object_origins"] - space.overlay.show_relationship_lines = style["space.overlay.show_relationship_lines"] - - def set_query(self): + def set_query(self, context): self.selector = ifcopenshell.util.selector.Selector() self.include_global_ids = [] self.exclude_global_ids = [] - for ifc_file in bpy.context.scene.DocProperties.ifc_files: + for ifc_file in context.scene.DocProperties.ifc_files: try: ifc = ifcopenshell.open(ifc_file.name) except: @@ -967,15 +979,15 @@ class ActivateDrawingStyle(bpy.types.Operator): results = self.selector.parse(ifc, self.drawing_style.exclude_query) self.exclude_global_ids.extend([e.GlobalId for e in results]) if self.drawing_style.include_query: - self.parse_filter_query("INCLUDE") + self.parse_filter_query("INCLUDE", context) if self.drawing_style.exclude_query: - self.parse_filter_query("EXCLUDE") + self.parse_filter_query("EXCLUDE", context) - def parse_filter_query(self, mode): + def parse_filter_query(self, mode, context): if mode == "INCLUDE": - objects = bpy.context.scene.objects + objects = context.scene.objects elif mode == "EXCLUDE": - objects = bpy.context.visible_objects + objects = context.visible_objects for obj in objects: if mode == "INCLUDE": obj.hide_viewport = False # Note: this breaks alt-H @@ -990,8 +1002,8 @@ class ActivateDrawingStyle(bpy.types.Operator): if global_id in self.exclude_global_ids: obj.hide_viewport = True # Note: this breaks alt-H - def get_view_3d(self): - for area in bpy.context.screen.areas: + def get_view_3d(self, context): + for area in context.screen.areas: if area.type != "VIEW_3D": continue for space in area.spaces: @@ -1021,7 +1033,7 @@ class RemoveSheet(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties props.sheets.remove(self.index) return {"FINISHED"} @@ -1032,8 +1044,8 @@ class AddSchedule(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - new = bpy.context.scene.DocProperties.schedules.add() - new.name = "SCHEDULE {}".format(len(bpy.context.scene.DocProperties.schedules)) + new = context.scene.DocProperties.schedules.add() + new.name = "SCHEDULE {}".format(len(context.scene.DocProperties.schedules)) return {"FINISHED"} @@ -1044,7 +1056,7 @@ class RemoveSchedule(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties props.schedules.remove(self.index) return {"FINISHED"} @@ -1058,8 +1070,8 @@ class SelectScheduleFile(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - props = bpy.context.scene.DocProperties - props.schedules[props.active_schedule_index].file = self.filepath + props = context.scene.DocProperties + props.active_schedule.file = self.filepath return {"FINISHED"} def invoke(self, context, event): @@ -1071,13 +1083,17 @@ class BuildSchedule(bpy.types.Operator): bl_idname = "bim.build_schedule" bl_label = "Build Schedule" + @classmethod + def poll(cls, context): + return context.scene.DocProperties.active_schedule.file + def execute(self, context): - props = bpy.context.scene.DocProperties - schedule = props.schedules[props.active_schedule_index] + props = context.scene.DocProperties + schedule = props.active_schedule schedule_creator = scheduler.Scheduler() - outfile = os.path.join(bpy.context.scene.BIMProperties.data_dir, "schedules", schedule.name + ".svg") + outfile = os.path.join(context.scene.BIMProperties.data_dir, "schedules", schedule.name + ".svg") schedule_creator.schedule(schedule.file, outfile) - open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.svg_command, outfile) + open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, outfile) return {"FINISHED"} @@ -1088,11 +1104,11 @@ class AddScheduleToSheet(bpy.types.Operator): # TODO: check undo redo def execute(self, context): - props = bpy.context.scene.DocProperties + props = context.scene.DocProperties sheet_builder = sheeter.SheetBuilder() - sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir + sheet_builder.data_dir = context.scene.BIMProperties.data_dir sheet_builder.add_schedule( - props.schedules[props.active_schedule_index].name, props.sheets[props.active_sheet_index].name + props.active_schedule.name, props.active_sheet.name ) return {"FINISHED"} @@ -1103,7 +1119,7 @@ class AddDrawingStyleAttribute(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - props = bpy.context.scene.camera.data.BIMCameraProperties + props = context.scene.camera.data.BIMCameraProperties context.scene.DocProperties.drawing_styles[props.active_drawing_style_index].attributes.add() return {"FINISHED"} @@ -1115,7 +1131,7 @@ class RemoveDrawingStyleAttribute(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - props = bpy.context.scene.camera.data.BIMCameraProperties + props = context.scene.camera.data.BIMCameraProperties context.scene.DocProperties.drawing_styles[props.active_drawing_style_index].attributes.remove(self.index) return {"FINISHED"} @@ -1125,13 +1141,13 @@ class RefreshDrawingList(bpy.types.Operator): bl_label = "Refresh Drawing List" def execute(self, context): - while len(bpy.context.scene.DocProperties.drawings) > 0: - bpy.context.scene.DocProperties.drawings.remove(0) - for obj in bpy.context.scene.objects: + doc_props = context.scene.DocProperties + doc_props.drawings.clear() + for obj in context.scene.objects: if not isinstance(obj.data, bpy.types.Camera): continue if "IfcAnnotation/" in obj.name: - new = bpy.context.scene.DocProperties.drawings.add() + new = doc_props.drawings.add() new.name = "/".join(obj.name.split("/")[1:]) new.camera = obj return {"FINISHED"} @@ -1143,13 +1159,12 @@ class CleanWireframes(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - objects = bpy.data.objects - if bpy.context.selected_objects: - objects = bpy.context.selected_objects - for obj in objects: - if not isinstance(obj.data, bpy.types.Mesh): - continue - if "EDGE_SPLIT" not in [m.type for m in obj.modifiers]: + if context.selected_objects: + objects = context.selected_objects + else: + objects = context.scene.objects + for obj in (o for o in objects if o.type == "MESH"): + if "EDGE_SPLIT" not in (m.type for m in obj.modifiers): obj.modifiers.new("EdgeSplit", "EDGE_SPLIT") return {"FINISHED"} @@ -1159,11 +1174,13 @@ class CopyGrid(bpy.types.Operator): bl_label = "Add Grid" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return helper.get_active_drawing(context.scene)[0] is not None + def execute(self, context): proj_coll = helper.get_project_collection(context.scene) view_coll, camera = helper.get_active_drawing(context.scene) - if view_coll is None: - return {"CANCELLED"} is_ortho = camera.data.type == "ORTHO" bounds = helper.ortho_view_frame(camera.data) if is_ortho else None clipping = is_ortho and camera.data.BIMCameraProperties.target_view in ("PLAN_VIEW", "REFLECTED_PLAN_VIEW") @@ -1240,13 +1257,15 @@ class AddSectionsAnnotations(bpy.types.Operator): bl_label = "Add Sections" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + camera = helper.get_active_drawing(context.scene)[1] + return camera and camera.data.type == "ORTHO" + def execute(self, context): scene = context.scene view_coll, camera = helper.get_active_drawing(scene) - is_ortho = camera.data.type == "ORTHO" - if not is_ortho: - return {"CANCELLED"} - bounds = helper.ortho_view_frame(camera.data) if is_ortho else None + bounds = helper.ortho_view_frame(camera.data) drawings = [ d diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index b64a1dcba6..150d800e32 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -1,7 +1,27 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import blenderbim.bim.module.drawing.annotation as annotation import blenderbim.bim.module.drawing.decoration as decoration +import enum from pathlib import Path from blenderbim.bim.prop import Attribute, StrProperty from bpy.types import PropertyGroup @@ -38,10 +58,10 @@ def getDiagramScales(self, context): global diagram_scales_enum if ( len(diagram_scales_enum) < 1 - or (bpy.context.scene.unit_settings.system == "IMPERIAL" and len(diagram_scales_enum) == 13) - or (bpy.context.scene.unit_settings.system == "METRIC" and len(diagram_scales_enum) == 31) + or (context.scene.unit_settings.system == "IMPERIAL" and len(diagram_scales_enum) == 13) + or (context.scene.unit_settings.system == "METRIC" and len(diagram_scales_enum) == 31) ): - if bpy.context.scene.unit_settings.system == "IMPERIAL": + if context.scene.unit_settings.system == "IMPERIAL": diagram_scales_enum = [ ("CUSTOM", "Custom", ""), ("1'=1'-0\"|1/1", "1'=1'-0\"", ""), @@ -199,6 +219,33 @@ class DrawingStyle(PropertyGroup): attributes: CollectionProperty(name="Attributes", type=StrProperty) +class RasterStyleProperty(enum.Enum): + WORLD_COLOR = "bpy.data.worlds[0].color" + RENDER_ENGINE = "scene.render.engine" + RENDER_TRANSPARENT = "scene.render.film_transparent" + VIEW_TRANSFORM = "scene.view_settings.view_transform" + SHADING_SHOW_OBJECT_OUTLINE = "scene.display.shading.show_object_outline" + SHADING_SHOW_CAVITY = "scene.display.shading.show_cavity" + SHADING_CAVITY_TYPE = "scene.display.shading.cavity_type" + SHADING_CURVATURE_RIDGE_FACTOR = "scene.display.shading.curvature_ridge_factor" + SHADING_CURVATURE_VALLEY_FACTOR = "scene.display.shading.curvature_valley_factor" + SHADING_LIGHT = "scene.display.shading.light" + SHADING_COLOR_TYPE = "scene.display.shading.color_type" + SHADING_SINGLE_COLOR = "scene.display.shading.single_color" + SHADING_SHOW_SHADOWS = "scene.display.shading.show_shadows" + SHADING_SHADOW_INTENSITY = "scene.display.shading.shadow_intensity" + DISPLAY_LIGHT_DIRECTION = "scene.display.light_direction" + VIEW_USE_CURVE_MAPPING = "scene.view_settings.use_curve_mapping" + OVERLAY_SHOW_WIREFRAMES = "space.overlay.show_wireframes" + OVERLAY_WIREFRAME_THRESHOLD = "space.overlay.wireframe_threshold" + OVERLAY_SHOW_FLOOR = "space.overlay.show_floor" + OVERLAY_SHOW_AXIS_X = "space.overlay.show_axis_x" + OVERLAY_SHOW_AXIS_Y = "space.overlay.show_axis_y" + OVERLAY_SHOW_AXIS_Z = "space.overlay.show_axis_z" + OVERLAY_SHOW_OBJECT_ORIGINS = "space.overlay.show_object_origins" + OVERLAY_SHOW_RELATIONSHIP_LINES = "space.overlay.show_relationship_lines" + + class DocProperties(PropertyGroup): has_underlay: BoolProperty(name="Underlay", default=False) has_linework: BoolProperty(name="Linework", default=True) @@ -222,6 +269,17 @@ class DocProperties(PropertyGroup): name="Decorations Colour", subtype="COLOR", default=(1, 0, 0, 1), min=0.0, max=1.0, size=4 ) + @property + def active_schedule(self): + return self.schedules[self.active_schedule_index] + + @property + def active_drawing(self): + return self.drawings[self.active_drawing_index] + + @property + def active_sheet(self): + return self.sheets[self.active_sheet_index] class BIMCameraProperties(PropertyGroup): view_name: StringProperty(name="View Name") diff --git a/src/blenderbim/blenderbim/bim/module/drawing/scheduler.py b/src/blenderbim/blenderbim/bim/module/drawing/scheduler.py index 81555cb55c..902324e6b0 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/scheduler.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/scheduler.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import svgwrite from odf.opendocument import load diff --git a/src/blenderbim/blenderbim/bim/module/drawing/shaders.py b/src/blenderbim/blenderbim/bim/module/drawing/shaders.py index 8b9c79efc8..ff85417bbd 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/shaders.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/shaders.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bgl from mathutils import Matrix from gpu.types import GPUShader diff --git a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py index 5290337ab7..901771ddea 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import xml.etree.ElementTree as ET import urllib.parse import pystache diff --git a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py index c7f9ae1f22..e00dc0c84f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import re import bpy diff --git a/src/blenderbim/blenderbim/bim/module/drawing/ui.py b/src/blenderbim/blenderbim/bim/module/drawing/ui.py index cd4212e926..2662e885ec 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/ui.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy from bpy.types import Panel @@ -151,9 +170,9 @@ class BIM_PT_drawings(Panel): if props.drawings: if props.active_drawing_index < len(props.drawings): op = row.operator("bim.open_view", icon="URL", text="") - op.view = props.drawings[props.active_drawing_index].name + op.view = props.active_drawing.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") row = layout.row() row.operator("bim.add_ifc_file") @@ -187,7 +206,7 @@ class BIM_PT_schedules(Panel): layout.template_list("BIM_UL_generic", "", props, "schedules", props, "active_schedule_index") row = layout.row() - row.prop(props.schedules[props.active_schedule_index], "file") + row.prop(props.active_schedule, "file") row.operator("bim.select_schedule_file", icon="FILE_FOLDER", text="") @@ -324,7 +343,7 @@ class BIM_PT_annotation_utilities(Panel): if props.drawings: if props.active_drawing_index < len(props.drawings): op = row.operator("bim.open_view", icon="URL", text="") - op.view = props.drawings[props.active_drawing_index].name + op.view = props.active_drawing.name row.operator("bim.remove_drawing", icon="X", text="").index = props.active_drawing_index layout.template_list("BIM_UL_drawinglist", "", props, "drawings", props, "active_drawing_index") diff --git a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py index 433e308052..61cf9906d3 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/geometry/helper.py b/src/blenderbim/blenderbim/bim/module/geometry/helper.py index 1733ea1d9c..d27582d8b6 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/helper.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/helper.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import bmesh import mathutils diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 3d2be2b4d2..4af285fa94 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import numpy as np import ifcopenshell @@ -228,6 +247,8 @@ class SwitchRepresentation(bpy.types.Operator): modifier = self.element_obj.modifiers.new("IfcOpeningElement", "BOOLEAN") modifier.operation = "DIFFERENCE" modifier.object = opening + modifier.solver = "EXACT" + modifier.use_self = True else: for modifier in self.element_obj.modifiers: if modifier.type == "BOOLEAN" and "IfcOpeningElement" in modifier.name: diff --git a/src/blenderbim/blenderbim/bim/module/geometry/prop.py b/src/blenderbim/blenderbim/bim/module/geometry/prop.py index 983754d987..f120f57282 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/prop.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/geometry/ui.py b/src/blenderbim/blenderbim/bim/module/geometry/ui.py index ee387ab8f9..b05acc8d03 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/ui.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel from ifcopenshell.api.geometry.data import Data diff --git a/src/blenderbim/blenderbim/bim/module/georeference/__init__.py b/src/blenderbim/blenderbim/bim/module/georeference/__init__.py index 48ec27e3c9..babbbc870d 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index 22a883db5b..2026de99e4 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -1,9 +1,29 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell import ifcopenshell.util.unit import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.georeference.data import Data from math import radians, degrees, atan, tan, cos, sin @@ -18,8 +38,7 @@ class EnableEditingGeoreferencing(bpy.types.Operator): self.file = IfcStore.get_file() props = context.scene.BIMGeoreferenceProperties - while len(props.projected_crs) > 0: - props.projected_crs.remove(0) + props.projected_crs.clear() for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes(): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) @@ -49,8 +68,7 @@ class EnableEditingGeoreferencing(bpy.types.Operator): elif props.map_unit_type == "IfcConversionBasedUnit": props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"] - while len(props.map_conversion) > 0: - props.map_conversion.remove(0) + props.map_conversion.clear() for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes(): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) @@ -96,38 +114,13 @@ class EditGeoreferencing(bpy.types.Operator): self.file = IfcStore.get_file() props = context.scene.BIMGeoreferenceProperties - projected_crs = {} - for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - blender_attribute = props.projected_crs.get(attribute.name()) - if blender_attribute.is_null: - projected_crs[attribute.name()] = None - elif blender_attribute.data_type == "string": - projected_crs[attribute.name()] = blender_attribute.string_value - elif blender_attribute.data_type == "float": - projected_crs[attribute.name()] = blender_attribute.float_value - elif blender_attribute.data_type == "integer": - projected_crs[attribute.name()] = blender_attribute.int_value - elif blender_attribute.data_type == "boolean": - projected_crs[attribute.name()] = blender_attribute.bool_value + projected_crs = blenderbim.bim.helper.export_attributes(props.projected_crs) map_unit = "" if not props.is_map_unit_null: map_unit = props.map_unit_si if props.map_unit_type == "IfcSIUnit" else props.map_unit_imperial - map_conversion = {} - for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or data_type == "select": - continue - blender_attribute = props.map_conversion.get(attribute.name()) - if blender_attribute.is_null: - map_conversion[attribute.name()] = None - elif blender_attribute.data_type == "string": - # We store our floats as string to prevent single precision data loss - map_conversion[attribute.name()] = float(blender_attribute.string_value) + map_conversion = blenderbim.bim.helper.export_attributes(props.map_conversion, self.export_attributes) true_north = None if props.has_true_north: @@ -150,6 +143,12 @@ class EditGeoreferencing(bpy.types.Operator): bpy.ops.bim.disable_editing_georeferencing() return {"FINISHED"} + def export_attributes(self, attributes, prop): + if not prop.is_null and prop.data_type == "string": + # We store our floats as string to prevent single precision data loss + attributes[prop.name] = float(prop.string_value) + return True + class SetBlenderGridNorth(bpy.types.Operator): bl_idname = "bim.set_blender_grid_north" @@ -238,6 +237,12 @@ class ConvertLocalToGlobal(bpy.types.Operator): bl_label = "Convert Local To Global" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + props = context.scene.BIMGeoreferenceProperties + return file and props.coordinate_input.count(",") == 2 + def execute(self, context): if not Data.is_loaded: Data.load(IfcStore.get_file()) @@ -285,6 +290,13 @@ class ConvertGlobalToLocal(bpy.types.Operator): bl_label = "Convert Global To Local" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + props = context.scene.BIMGeoreferenceProperties + return file and file.by_type("IfcUnitAssignment") \ + and props.coordinate_input.count(",") == 2 + def execute(self, context): if not Data.is_loaded: Data.load(IfcStore.get_file()) @@ -331,6 +343,11 @@ class GetCursorLocation(bpy.types.Operator): bl_label = "Get Cursor Location" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + return file and file.by_type("IfcUnitAssignment") + def execute(self, context): props = context.scene.BIMGeoreferenceProperties scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file()) @@ -344,6 +361,12 @@ class SetCursorLocation(bpy.types.Operator): bl_label = "Set Cursor Location" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + props = context.scene.BIMGeoreferenceProperties + return file and file.by_type("IfcUnitAssignment") and props.coordinate_output.count(",") == 2 + def execute(self, context): props = context.scene.BIMGeoreferenceProperties scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file()) diff --git a/src/blenderbim/blenderbim/bim/module/georeference/prop.py b/src/blenderbim/blenderbim/bim/module/georeference/prop.py index 8406f823bf..900a1bdaaa 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/prop.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup @@ -33,8 +52,8 @@ class BIMGeoreferenceProperties(PropertyGroup): default="foot", ) is_map_unit_null: BoolProperty(name="Is Map Unit Null") - coordinate_input: StringProperty(name="Coordinate Input") - coordinate_output: StringProperty(name="Coordinate Output") + coordinate_input: StringProperty(name="Coordinate Input", description="Formatted \"x,y,z\" (without quotes)") + coordinate_output: StringProperty(name="Coordinate Output", description="Formatted \"x,y,z\" (without quotes)") has_blender_offset: BoolProperty(name="Has Blender Offset") blender_eastings: StringProperty(name="Blender Eastings", default="0") blender_northings: StringProperty(name="Blender Northings", default="0") diff --git a/src/blenderbim/blenderbim/bim/module/georeference/ui.py b/src/blenderbim/blenderbim/bim/module/georeference/ui.py index 19f843541a..cf5a9e8481 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/ui.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/ui.py @@ -1,7 +1,27 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import ifcopenshell.util.geolocation from bpy.types import Panel from ifcopenshell.api.georeference.data import Data from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes, draw_attribute class BIM_PT_gis(Panel): @@ -32,19 +52,9 @@ class BIM_PT_gis(Panel): row = self.layout.row(align=True) row.label(text="Projected CRS", icon="WORLD") row.operator("bim.edit_georeferencing", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_georeferencing", icon="X", text="") + row.operator("bim.disable_editing_georeferencing", icon="CANCEL", text="") - for attribute in props.projected_crs: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(props.projected_crs, self.layout) row = self.layout.row(align=True) row.prop(props, "map_unit_type", text="MapUnit") @@ -62,17 +72,7 @@ class BIM_PT_gis(Panel): row = self.layout.row(align=True) row.operator("bim.set_ifc_grid_north", text="Set IFC North") row.operator("bim.set_blender_grid_north", text="Set Blender North") - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attribute(attribute, self.layout.row()) row = self.layout.row() row.label(text="True North", icon="LIGHT_SUN") diff --git a/src/blenderbim/blenderbim/bim/module/group/__init__.py b/src/blenderbim/blenderbim/bim/module/group/__init__.py index d8871b4131..4cf5131a2f 100644 --- a/src/blenderbim/blenderbim/bim/module/group/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/group/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/group/operator.py b/src/blenderbim/blenderbim/bim/module/group/operator.py index 76f2f245a4..0cd773791f 100644 --- a/src/blenderbim/blenderbim/bim/module/group/operator.py +++ b/src/blenderbim/blenderbim/bim/module/group/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.util.attribute import ifcopenshell.api @@ -12,8 +31,7 @@ class LoadGroups(bpy.types.Operator): def execute(self, context): props = context.scene.BIMGroupProperties - while len(props.groups) > 0: - props.groups.remove(0) + props.groups.clear() for ifc_definition_id, group in Data.groups.items(): new = props.groups.add() new.ifc_definition_id = ifc_definition_id @@ -100,8 +118,7 @@ class EnableEditingGroup(bpy.types.Operator): def execute(self, context): props = context.scene.BIMGroupProperties - while len(props.group_attributes) > 0: - props.group_attributes.remove(0) + props.group_attributes.clear() data = Data.groups[self.group] diff --git a/src/blenderbim/blenderbim/bim/module/group/prop.py b/src/blenderbim/blenderbim/bim/module/group/prop.py index f754cd37b7..05decfb78d 100644 --- a/src/blenderbim/blenderbim/bim/module/group/prop.py +++ b/src/blenderbim/blenderbim/bim/module/group/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/group/ui.py b/src/blenderbim/blenderbim/bim/module/group/ui.py index 21cd9a9870..479a4c787a 100644 --- a/src/blenderbim/blenderbim/bim/module/group/ui.py +++ b/src/blenderbim/blenderbim/bim/module/group/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data diff --git a/src/blenderbim/blenderbim/bim/module/layer/__init__.py b/src/blenderbim/blenderbim/bim/module/layer/__init__.py index ea302841c6..136e70fa88 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/layer/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/layer/operator.py b/src/blenderbim/blenderbim/bim/module/layer/operator.py index 4ec6daa8c2..2ebd391809 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/operator.py +++ b/src/blenderbim/blenderbim/bim/module/layer/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.util.attribute @@ -14,8 +33,7 @@ class LoadLayers(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMLayerProperties - while len(props.layers) > 0: - props.layers.remove(0) + props.layers.clear() for layer_id, layer in Data.layers.items(): new = props.layers.add() new.name = layer["Name"] or "Unnamed" @@ -43,8 +61,7 @@ class EnableEditingLayer(bpy.types.Operator): def execute(self, context): props = context.scene.BIMLayerProperties - while len(props.layer_attributes) > 0: - props.layer_attributes.remove(0) + props.layer_attributes.clear() data = Data.layers[self.layer] diff --git a/src/blenderbim/blenderbim/bim/module/layer/prop.py b/src/blenderbim/blenderbim/bim/module/layer/prop.py index c832e45c22..61c310bdb2 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/prop.py +++ b/src/blenderbim/blenderbim/bim/module/layer/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/layer/ui.py b/src/blenderbim/blenderbim/bim/module/layer/ui.py index 7ed1cc4da6..542556adca 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/ui.py +++ b/src/blenderbim/blenderbim/bim/module/layer/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList, Mesh from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.layer.data import Data @@ -25,7 +44,7 @@ class BIM_PT_layers(Panel): row.label(text="{} Layers Found".format(len(Data.layers.keys()))) if self.props.is_editing: row.operator("bim.add_presentation_layer", text="", icon="ADD") - row.operator("bim.disable_layer_editing_ui", text="", icon="X") + row.operator("bim.disable_layer_editing_ui", text="", icon="CANCEL") else: row.operator("bim.load_layers", text="", icon="GREASEPENCIL") @@ -73,7 +92,7 @@ class BIM_UL_layers(UIList): if context.scene.BIMLayerProperties.active_layer_id == item.ifc_definition_id: row.operator("bim.edit_presentation_layer", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_layer", text="", icon="X") + row.operator("bim.disable_editing_layer", text="", icon="CANCEL") elif context.scene.BIMLayerProperties.active_layer_id: row.operator("bim.remove_presentation_layer", text="", icon="X").layer = item.ifc_definition_id else: diff --git a/src/blenderbim/blenderbim/bim/module/lca/__init__.py b/src/blenderbim/blenderbim/bim/module/lca/__init__.py new file mode 100644 index 0000000000..b32db0bacd --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/lca/__init__.py @@ -0,0 +1,34 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +from . import ui, prop, operator + +classes = ( + operator.CalculateLCA, + prop.BIMLCAProperties, + ui.BIM_PT_lca, +) + + +def register(): + bpy.types.Scene.BIMLCAProperties = bpy.props.PointerProperty(type=prop.BIMLCAProperties) + + +def unregister(): + del bpy.types.Scene.BIMLCAProperties diff --git a/src/blenderbim/blenderbim/bim/module/lca/operator.py b/src/blenderbim/blenderbim/bim/module/lca/operator.py new file mode 100644 index 0000000000..06926f5009 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/lca/operator.py @@ -0,0 +1,45 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +import olca +import ifcopenshell + + +class CalculateLCA(bpy.types.Operator): + bl_idname = "bim.calculate_lca" + bl_label = "Calculate LCA" + bl_options = {"REGISTER", "UNDO"} + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + filter_glob: bpy.props.StringProperty(default="*.xlsx", options={"HIDDEN"}) + + def execute(self, context): + props = context.scene.BIMLCAProperties + client = olca.Client(context.preferences.addons["blenderbim"].preferences.openlca_port) + setup = olca.CalculationSetup() + setup.calculation_type = olca.CalculationType.SIMPLE_CALCULATION + setup.impact_method = client.find(olca.ImpactMethod, "CML-IA baseline") + setup.product_system = client.find(olca.ProductSystem, props.product_systems) + setup.amount = props.amount + result = client.calculate(setup) + client.excel_export(result, self.filepath) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} diff --git a/src/blenderbim/blenderbim/bim/module/lca/prop.py b/src/blenderbim/blenderbim/bim/module/lca/prop.py new file mode 100644 index 0000000000..90c3b77f9d --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/lca/prop.py @@ -0,0 +1,58 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +import olca +from blenderbim.bim.prop import StrProperty, Attribute +from bpy.types import PropertyGroup +from bpy.props import ( + PointerProperty, + StringProperty, + EnumProperty, + BoolProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + CollectionProperty, +) + +productsystems_enum = [] + + +def purge(): + global productsystems_enum + productsystems_enum = [] + + +def get_product_systems(self, context): + global productsystems_enum + if not len(productsystems_enum): + client = olca.Client(context.preferences.addons["blenderbim"].preferences.openlca_port) + try: + productsystems_enum = [ + (ps.name, ps.name, "") for ps in client.get_all(olca.ProductSystem) + ] + except: + pass + return productsystems_enum + + +class BIMLCAProperties(PropertyGroup): + amount: FloatProperty(name="Amount") + product_systems: EnumProperty(items=get_product_systems, name="Product Systems") diff --git a/src/blenderbim/blenderbim/bim/module/lca/ui.py b/src/blenderbim/blenderbim/bim/module/lca/ui.py new file mode 100644 index 0000000000..a48bf668b1 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/lca/ui.py @@ -0,0 +1,38 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +from bpy.types import Panel + + +class BIM_PT_lca(Panel): + bl_label = "BIM Life Cycle Assessment" + bl_idname = "BIM_PT_lca" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + def draw(self, context): + props = context.scene.BIMLCAProperties + row = self.layout.row() + row.prop(props, "product_systems", text="") + row = self.layout.row() + row.prop(props, "amount", text="") + row = self.layout.row() + row.operator("bim.calculate_lca") diff --git a/src/blenderbim/blenderbim/bim/module/material/__init__.py b/src/blenderbim/blenderbim/bim/module/material/__init__.py index 76d4dca153..ea1ff8cd0d 100644 --- a/src/blenderbim/blenderbim/bim/module/material/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/material/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index 0d071dedbc..e735461ef8 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -401,16 +420,14 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): else: material_set_data = {} - while len(props.material_set_usage_attributes) > 0: - props.material_set_usage_attributes.remove(0) + props.material_set_usage_attributes.clear() if "Usage" in product_data["type"]: blenderbim.bim.helper.import_attributes( product_data["type"], props.material_set_usage_attributes, material_set_usage, self.import_attributes ) - while len(props.material_set_attributes) > 0: - props.material_set_attributes.remove(0) + props.material_set_attributes.clear() for attribute in IfcStore.get_schema().declaration_by_name(material_set_class).all_attributes(): if "" not in str(attribute.type_of_attribute): @@ -565,8 +582,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator): return {"FINISHED"} def load_set_item_attributes(self, material_set_item, material_set_item_data): - while len(self.props.material_set_item_attributes) > 0: - self.props.material_set_item_attributes.remove(0) + self.props.material_set_item_attributes.clear() for attribute in IfcStore.get_schema().declaration_by_name(material_set_item.is_a()).all_attributes(): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) @@ -587,8 +603,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator): new.bool_value = False if new.is_null else material_set_item_data[attribute.name()] def load_profile_attributes(self, material_set_item, material_set_item_data): - while len(self.props.material_set_item_profile_attributes) > 0: - self.props.material_set_item_profile_attributes.remove(0) + self.props.material_set_item_profile_attributes.clear() if not material_set_item_data["Profile"]: return @@ -655,17 +670,7 @@ class EditMaterialSetItem(bpy.types.Operator): props = obj.BIMObjectMaterialProperties product_data = Data.products[obj.BIMObjectProperties.ifc_definition_id] - attributes = {} - for attribute in props.material_set_item_attributes: - if attribute.data_type == "string": - value = attribute.string_value - elif attribute.data_type == "float": - value = attribute.float_value - elif attribute.data_type == "integer": - value = attribute.int_value - elif attribute.data_type == "boolean": - value = attribute.bool_value - attributes[attribute.name] = None if attribute.is_null else value + attributes = blenderbim.bim.helper.export_attributes(props.material_set_item_attributes) if product_data["type"] == "IfcMaterialConstituentSet": ifcopenshell.api.run( @@ -690,19 +695,7 @@ class EditMaterialSetItem(bpy.types.Operator): ) Data.load_layers() elif product_data["type"] == "IfcMaterialProfileSet" or product_data["type"] == "IfcMaterialProfileSetUsage": - profile_attributes = {} - for attribute in props.material_set_item_profile_attributes: - if attribute.data_type == "string": - value = attribute.string_value - elif attribute.data_type == "float": - value = attribute.float_value - elif attribute.data_type == "integer": - value = attribute.int_value - elif attribute.data_type == "boolean": - value = attribute.bool_value - elif attribute.data_type == "enum": - value = attribute.enum_value - profile_attributes[attribute.name] = None if attribute.is_null else value + profile_attributes = blenderbim.bim.helper.export_attributes(props.material_set_item_profile_attributes) ifcopenshell.api.run( "material.edit_profile", self.file, diff --git a/src/blenderbim/blenderbim/bim/module/material/prop.py b/src/blenderbim/blenderbim/bim/module/material/prop.py index 9373737ab1..9412dfe35a 100644 --- a/src/blenderbim/blenderbim/bim/module/material/prop.py +++ b/src/blenderbim/blenderbim/bim/module/material/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from ifcopenshell.api.material.data import Data from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 1a803aa836..f5630e2aec 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -1,8 +1,28 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import blenderbim.bim.helper from bpy.types import Panel from ifcopenshell.api.material.data import Data from ifcopenshell.api.profile.data import Data as ProfileData from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes class BIM_PT_material(Panel): @@ -181,17 +201,7 @@ class BIM_PT_object_material(Panel): op.material_set_item = set_item_id row.operator("bim.disable_editing_material_set_item", icon="CANCEL", text="") - for attribute in self.props.material_set_item_attributes: - row = box.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.material_set_item_attributes, self.layout) if self.set_item_name == "profile": self.draw_assign_profile_ui(box, item) @@ -213,20 +223,7 @@ class BIM_PT_object_material(Panel): row.operator("bim.disable_editing_material_set_item", icon="CANCEL", text="") def draw_editable_profile_ui(self, layout, item): - for attribute in self.props.material_set_item_profile_attributes: - row = layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.material_set_item_profile_attributes, self.layout) def draw_read_only_set_item_ui(self, set_item_id, index, is_first=False, is_last=False): if self.product_data["type"] == "IfcMaterialList": diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index 3fede4f2ef..f1698528bb 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import handler, prop, ui, grid, product, wall, slab, stair, door, window, opening, pie, workspace diff --git a/src/blenderbim/blenderbim/bim/module/model/door.py b/src/blenderbim/blenderbim/bim/module/model/door.py index 9c4a7f7935..197f1e6400 100644 --- a/src/blenderbim/blenderbim/bim/module/model/door.py +++ b/src/blenderbim/blenderbim/bim/module/model/door.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import math import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/model/grid.py b/src/blenderbim/blenderbim/bim/module/model/grid.py index 78c2e0bdff..f1b0353f9f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/grid.py +++ b/src/blenderbim/blenderbim/bim/module/model/grid.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from bpy.types import Operator diff --git a/src/blenderbim/blenderbim/bim/module/model/handler.py b/src/blenderbim/blenderbim/bim/module/model/handler.py index bde632c0b3..16b1c16b02 100644 --- a/src/blenderbim/blenderbim/bim/module/model/handler.py +++ b/src/blenderbim/blenderbim/bim/module/model/handler.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell import ifcopenshell.api diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 9c0c482e3c..58f0bfd137 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import bmesh import blenderbim.bim.handler @@ -5,6 +24,7 @@ import ifcopenshell import ifcopenshell.util.representation from blenderbim.bim.ifc import IfcStore from math import pi +from mathutils import Vector from bpy.types import Operator from bpy.props import FloatProperty from bpy_extras.object_utils import AddObjectHelper, object_data_add @@ -56,40 +76,126 @@ class AddElementOpening(bpy.types.Operator): bl_idname = "bim.add_element_opening" bl_label = "Add Element Opening" bl_options = {"REGISTER", "UNDO"} + voided_building_element: bpy.props.StringProperty() + filling_building_element: bpy.props.StringProperty() def execute(self, context): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - selected_objs = context.selected_objects - if len(selected_objs) == 0 or not context.active_object: + voided_obj = self.get_voided_building_element(context) + filling_obj = self.get_filling_building_element(context) + + if not voided_obj: return {"FINISHED"} - obj = context.active_object - if not obj.BIMObjectProperties.ifc_definition_id: - return {"FINISHED"} - element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) - local_location = obj.matrix_world.inverted() @ context.scene.cursor.location - raycast = obj.closest_point_on_mesh(local_location, distance=0.01) + + element = IfcStore.get_file().by_id(voided_obj.BIMObjectProperties.ifc_definition_id) + local_location = voided_obj.matrix_world.inverted() @ context.scene.cursor.location + raycast = voided_obj.closest_point_on_mesh(local_location, distance=0.01) if not raycast[0]: return {"FINISHED"} - # The opening shall be based on the smallest bounding dimension of the element - dimension = min(obj.dimensions) - bpy.ops.mesh.primitive_cube_add(size=dimension * 2) - opening = context.selected_objects[0] + if filling_obj: + opening = self.generate_opening_from_filling(filling_obj, voided_obj) + else: + # The opening shall be based on the smallest bounding dimension of the element + dimension = min(voided_obj.dimensions) + bpy.ops.mesh.primitive_cube_add(size=dimension * 2) + opening = context.selected_objects[0] - # Place the opening in the middle of the element - global_location = obj.matrix_world @ raycast[1] - normal = raycast[2] - normal.negate() - global_normal = obj.matrix_world.to_quaternion() @ normal - opening.location = global_location + (global_normal * (dimension / 2)) + # Place the opening in the middle of the element + global_location = voided_obj.matrix_world @ raycast[1] + normal = raycast[2] + normal.negate() + global_normal = voided_obj.matrix_world.to_quaternion() @ normal + opening.location = global_location + (global_normal * (dimension / 2)) + opening.rotation_euler = voided_obj.rotation_euler + opening.name = "Opening" - opening.rotation_euler = obj.rotation_euler - opening.name = "Opening" - bpy.ops.bim.add_opening(opening=opening.name, obj=obj.name) + bpy.ops.bim.add_opening(opening=opening.name, obj=voided_obj.name) + if filling_obj: + bpy.ops.bim.add_filling(opening=opening.name, obj=filling_obj.name) return {"FINISHED"} + def get_voided_building_element(self, context): + obj = None + if self.voided_building_element: + obj = bpy.data.objects.get(self.voided_building_element) + else: + total_selected = len(context.selected_objects) + if total_selected == 1 or total_selected == 2: + obj = context.active_object + if obj and obj.BIMObjectProperties.ifc_definition_id: + return obj + + def get_filling_building_element(self, context): + obj = None + if self.filling_building_element: + obj = bpy.data.objects.get(self.filling_building_element) + else: + total_selected = len(context.selected_objects) + if total_selected == 2: + if context.selected_objects[0] == context.active_object: + obj = context.selected_objects[1] + else: + obj = context.selected_objects[0] + if obj and obj.BIMObjectProperties.ifc_definition_id: + return obj + + def generate_opening_from_filling(self, filling_obj, voided_obj): + x, y, z = filling_obj.dimensions + dimension = min(voided_obj.dimensions) + if dimension == voided_obj.dimensions[0]: + verts = [ + Vector((-0.1, 0, 0)), + Vector((-0.1, 0, z)), + Vector((-0.1, y, 0)), + Vector((-0.1, y, z)), + Vector((dimension+0.1, 0, 0)), + Vector((dimension+0.1, 0, z)), + Vector((dimension+0.1, y, 0)), + Vector((dimension+0.1, y, z)), + ] + elif dimension == voided_obj.dimensions[1]: + verts = [ + Vector((0, -0.1, 0)), + Vector((0, -0.1, z)), + Vector((0, dimension+0.1, 0)), + Vector((0, dimension+0.1, z)), + Vector((x, -0.1, 0)), + Vector((x, -0.1, z)), + Vector((x, dimension+0.1, 0)), + Vector((x, dimension+0.1, z)), + ] + elif dimension == voided_obj.dimensions[2]: + verts = [ + Vector((0, 0, -0.1)), + Vector((0, 0, dimension+0.1)), + Vector((0, y, -0.1)), + Vector((0, y, dimension+0.1)), + Vector((x, 0, -0.1)), + Vector((x, 0, dimension+0.1)), + Vector((x, y, -0.1)), + Vector((x, y, dimension+0.1)), + ] + edges = [] + faces = [ + [0, 1, 3, 2], + [2, 3, 7, 6], + [6, 7, 5, 4], + [4, 5, 1, 0], + [2, 6, 4, 0], + [7, 3, 1, 5], + ] + mesh = bpy.data.meshes.new(name="Opening") + mesh.from_pydata(verts, edges, faces) + obj = bpy.data.objects.new("Opening", mesh) + obj.matrix_world = filling_obj.matrix_world + + filling_obj.rotation_euler = voided_obj.rotation_euler + obj.parent = filling_obj + obj.matrix_parent_inverse = filling_obj.matrix_world.inverted() + return obj def add_object(self, context): diff --git a/src/blenderbim/blenderbim/bim/module/model/pie.py b/src/blenderbim/blenderbim/bim/module/model/pie.py index d2f2f2f296..5c5480f07f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/pie.py +++ b/src/blenderbim/blenderbim/bim/module/model/pie.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.ifc import IfcStore @@ -28,8 +47,8 @@ class PieAddOpening(bpy.types.Operator): elif len(obj.children) == 1 and not obj.children[0].BIMObjectProperties.ifc_definition_id: opening_name = obj.children[0].name else: - opj_name = obj.name - bpy.ops.bim.add_opening(obj=opj_name, opening=opening_name) + obj_name = obj.name + bpy.ops.bim.add_opening(obj=obj_name, opening=opening_name) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 0226167c5f..c03062d007 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import mathutils import ifcopenshell @@ -51,37 +70,26 @@ class AddTypeInstance(bpy.types.Operator): tprops = context.scene.BIMTypeProperties ifc_class = self.ifc_class or tprops.ifc_class relating_type_id = self.relating_type or tprops.relating_type + if not ifc_class or not relating_type_id: return {"FINISHED"} + self.file = IfcStore.get_file() instance_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, self.file.schema)[0] relating_type = self.file.by_id(int(relating_type_id)) material = ifcopenshell.util.element.get_material(relating_type) - if material.is_a("IfcMaterialProfileSet"): - obj = profile.DumbProfileGenerator(relating_type).generate() - if obj: + + if material and material.is_a("IfcMaterialProfileSet"): + if profile.DumbProfileGenerator(relating_type).generate(): return {"FINISHED"} - elif material.is_a("IfcMaterialLayerSet"): - layer_set_direction = None - - parametric = ifcopenshell.util.element.get_psets(relating_type).get("EPset_Parametric") - if parametric: - layer_set_direction = parametric.get("LayerSetDirection", layer_set_direction) - if layer_set_direction is None: - if ifc_class in ["IfcSlabType", "IfcRoofType", "IfcRampType", "IfcPlateType"]: - layer_set_direction = "AXIS3" - else: - layer_set_direction = "AXIS2" - - if layer_set_direction == "AXIS3": - obj = slab.DumbSlabGenerator(relating_type).generate() - elif layer_set_direction == "AXIS2": - obj = wall.DumbWallGenerator(relating_type).generate() - else: - obj = None # Dumb block generator? Eh? :) - - if obj: + elif material and material.is_a("IfcMaterialLayerSet"): + if self.generate_layered_element(ifc_class, relating_type): return {"FINISHED"} + + building_obj = None + if len(context.selected_objects) == 1 and context.active_object: + building_obj = context.active_object + # A cube verts = [ Vector((-1, -1, -1)), @@ -95,12 +103,12 @@ class AddTypeInstance(bpy.types.Operator): ] edges = [] faces = [ - [0, 2, 3, 1], + [0, 1, 3, 2], [2, 3, 7, 6], - [4, 5, 7, 6], - [0, 1, 5, 4], - [1, 3, 7, 5], - [0, 2, 6, 4], + [6, 7, 5, 4], + [4, 5, 1, 0], + [2, 6, 4, 0], + [7, 3, 1, 5], ] mesh = bpy.data.meshes.new(name="Instance") mesh.from_pydata(verts, edges, faces) @@ -111,10 +119,43 @@ class AddTypeInstance(bpy.types.Operator): collection_obj = bpy.data.objects.get(collection.name) bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class) bpy.ops.bim.assign_type(relating_type=int(tprops.relating_type), related_object=obj.name) - if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id: - obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box]) + + if building_obj: + if instance_class == "IfcWindow": + # TODO For now we are hardcoding windows as a prototype + bpy.ops.bim.add_element_opening( + voided_building_element=building_obj.name, filling_building_element=obj.name + ) + else: + if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id: + obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box]) + + bpy.ops.object.select_all(action='DESELECT') + obj.select_set(True) + context.view_layer.objects.active = obj return {"FINISHED"} + def generate_layered_element(self, ifc_class, relating_type): + layer_set_direction = None + + parametric = ifcopenshell.util.element.get_psets(relating_type).get("EPset_Parametric") + if parametric: + layer_set_direction = parametric.get("LayerSetDirection", layer_set_direction) + if layer_set_direction is None: + if ifc_class in ["IfcSlabType", "IfcRoofType", "IfcRampType", "IfcPlateType"]: + layer_set_direction = "AXIS3" + else: + layer_set_direction = "AXIS2" + + if layer_set_direction == "AXIS3": + if slab.DumbSlabGenerator(relating_type).generate(): + return True + elif layer_set_direction == "AXIS2": + if wall.DumbWallGenerator(relating_type).generate(): + return True + else: + pass # Dumb block generator? Eh? :) + class AlignProduct(bpy.types.Operator): bl_idname = "bim.align_product" @@ -168,8 +209,14 @@ class DynamicallyVoidProduct(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): obj = bpy.data.objects.get(self.obj) + if obj is None: + return {"FINISHED"} product = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) if not product.HasOpenings: return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/profile.py b/src/blenderbim/blenderbim/bim/module/model/profile.py index 493d3db501..6c9c82f139 100644 --- a/src/blenderbim/blenderbim/bim/module/model/profile.py +++ b/src/blenderbim/blenderbim/bim/module/model/profile.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import bmesh import math diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index bc7bf5d5f7..55389ded4c 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.util.type from blenderbim.bim.prop import StrProperty, Attribute diff --git a/src/blenderbim/blenderbim/bim/module/model/root.py b/src/blenderbim/blenderbim/bim/module/model/root.py index 729d477b94..4870d1094c 100644 --- a/src/blenderbim/blenderbim/bim/module/model/root.py +++ b/src/blenderbim/blenderbim/bim/module/model/root.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.style.data import Data as StyleData diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index 499ecba7af..c99e30f79a 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import bmesh import math @@ -34,26 +53,7 @@ def mode_callback(obj, data): return if obj.mode == "EDIT": IfcStore.edited_objs.add(obj) - modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"] - if modifier: - return - depth = obj.dimensions.z - bm = bmesh.from_edit_mesh(obj.data) - bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) - bm.faces.ensure_lookup_table() - non_bottom_faces = [] - for face in bm.faces: - if face.normal.z > -0.9: - non_bottom_faces.append(face) - else: - face.normal_flip() - bmesh.ops.delete(bm, geom=non_bottom_faces, context="FACES") - bmesh.update_edit_mesh(obj.data) - bm.free() - modifier = obj.modifiers.new("Slab Depth", "SOLIDIFY") - modifier.use_even_offset = True - modifier.offset = 1 - modifier.thickness = depth + ensure_solidify_modifier(obj) else: new_origin = obj.matrix_world @ Vector(obj.bound_box[0]) obj.data.transform( @@ -64,6 +64,41 @@ def mode_callback(obj, data): obj.matrix_world.translation = new_origin +def ensure_solidify_modifier(obj): + modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"] + if modifier: + return modifier[0] + depth = obj.dimensions.z + + if obj.mode == "EDIT": + bm = bmesh.from_edit_mesh(obj.data) + else: + bm = bmesh.new() + bm.from_mesh(obj.data) + + bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) + bm.faces.ensure_lookup_table() + non_bottom_faces = [] + for face in bm.faces: + if face.normal.z > -0.9: + non_bottom_faces.append(face) + else: + face.normal_flip() + bmesh.ops.delete(bm, geom=non_bottom_faces, context="FACES") + + if obj.mode == "EDIT": + bmesh.update_edit_mesh(obj.data) + else: + bm.to_mesh(obj.data) + + bm.free() + modifier = obj.modifiers.new("Slab Depth", "SOLIDIFY") + modifier.use_even_offset = True + modifier.offset = 1 + modifier.thickness = depth + return modifier + + def ensure_solid(usecase_path, ifc_file, settings): product = ifc_file.by_id(settings["blender_object"].BIMObjectProperties.ifc_definition_id) parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric") @@ -326,10 +361,6 @@ class DumbSlabPlaner: if round(delta_thickness, 2) == 0: return - modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"] - if modifier: - modifier = modifier[0] - else: - pass + modifier = ensure_solidify_modifier(obj) modifier.thickness += delta_thickness obj.location[2] -= delta_thickness diff --git a/src/blenderbim/blenderbim/bim/module/model/stair.py b/src/blenderbim/blenderbim/bim/module/model/stair.py index b0074f34c2..aacb1b40ad 100644 --- a/src/blenderbim/blenderbim/bim/module/model/stair.py +++ b/src/blenderbim/blenderbim/bim/module/model/stair.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Operator from bpy.props import FloatProperty, IntProperty diff --git a/src/blenderbim/blenderbim/bim/module/model/task.py b/src/blenderbim/blenderbim/bim/module/model/task.py index 2b3dd9a038..a7d75b0318 100644 --- a/src/blenderbim/blenderbim/bim/module/model/task.py +++ b/src/blenderbim/blenderbim/bim/module/model/task.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import ifcopenshell import ifcopenshell.api import ifcopenshell.util.date diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 9e5db798a4..00a34969bf 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -1,3 +1,23 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.bim.module.type.prop as type_prop from bpy.types import Panel from blenderbim.bim.ifc import IfcStore @@ -16,9 +36,21 @@ class BIM_PT_authoring(Panel): def draw(self, context): tprops = context.scene.BIMTypeProperties col = self.layout.column(align=True) - col.prop(tprops, "ifc_class", text="", icon="FILE_VOLUME") - col.prop(tprops, "relating_type", text="", icon="FILE_3D") - col.operator("bim.add_type_instance", icon="ADD") + enabled = True + + if type_prop.getIfcTypes(tprops, context): + col.prop(tprops, "ifc_class", text="", icon="FILE_VOLUME") + else: + col.label(text="No IFC Class", icon="FILE_VOLUME") + enabled = False + if type_prop.getAvailableTypes(tprops, context): + col.prop(tprops, "relating_type", text="", icon="FILE_3D") + else: + col.label(text="No Relating Type", icon="FILE_3D") + enabled = False + row = col.row() + row.operator("bim.add_type_instance", icon="ADD") + row.enabled = enabled class BIM_PT_authoring_architectural(Panel): @@ -57,9 +89,8 @@ class BIM_PT_misc_utilities(Panel): layout = self.layout props = context.scene.BIMProperties - row = layout.row() + row = layout.split(factor=0.2, align=True) row.prop(props, "override_colour", text="") - row = layout.row(align=True) row.operator("bim.set_override_colour") row = layout.row(align=True) row.operator("bim.set_viewport_shadow_from_sun") diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index ebc556fabe..3678422016 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import math import bmesh @@ -55,12 +74,14 @@ class JoinWall(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} join_type: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): - selected_objs = context.selected_objects + selected_objs = [o for o in context.selected_objects if o.BIMObjectProperties.ifc_definition_id] for obj in selected_objs: bpy.ops.bim.dynamically_void_product(obj=obj.name) - if len(selected_objs) == 0: - return {"FINISHED"} if not self.join_type: for obj in selected_objs: DumbWallJoiner(obj, obj).unjoin() @@ -95,11 +116,14 @@ class AlignWall(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} align_type: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + selected_valid_objects = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")] + return context.active_object and len(selected_valid_objects) > 1 + def execute(self, context): - selected_objs = context.selected_objects - if len(selected_objs) < 2 or not context.active_object: - return {"FINISHED"} - for obj in selected_objs: + selected_objects = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")] + for obj in selected_objects: if obj == context.active_object: continue aligner = DumbWallAligner(obj, context.active_object) @@ -118,10 +142,12 @@ class FlipWall(bpy.types.Operator): bl_label = "Flip Wall" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): - selected_objs = context.selected_objects - if len(selected_objs) == 0: - return {"FINISHED"} + selected_objs = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")] for obj in selected_objs: DumbWallFlipper(obj).flip() IfcStore.edited_objs.add(obj) @@ -133,12 +159,14 @@ class SplitWall(bpy.types.Operator): bl_label = "Split Wall" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): - selected_objs = context.selected_objects - if len(selected_objs) == 0: - return {"FINISHED"} + selected_objs = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")] for obj in selected_objs: - DumbWallSplitter(obj, bpy.context.scene.cursor.location).split() + DumbWallSplitter(obj, context.scene.cursor.location).split() IfcStore.edited_objs.add(obj) return {"FINISHED"} @@ -938,11 +966,11 @@ class DumbWallPlaner: for edge in vert.link_edges: other_vert = edge.verts[1] if edge.verts[0] == vert else edge.verts[0] if delta_thickness > 0: - potential_slide_vector = vert.co - other_vert.co + potential_slide_vector = (vert.co - other_vert.co).normalized() if potential_slide_vector.y < 0: continue else: - potential_slide_vector = other_vert.co - vert.co + potential_slide_vector = (other_vert.co - vert.co).normalized() if potential_slide_vector.y > 0: continue if abs(potential_slide_vector.x) > 0.9 or abs(potential_slide_vector.z) > 0.9: diff --git a/src/blenderbim/blenderbim/bim/module/model/window.py b/src/blenderbim/blenderbim/bim/module/model/window.py index ba491f4413..8890051ac3 100644 --- a/src/blenderbim/blenderbim/bim/module/model/window.py +++ b/src/blenderbim/blenderbim/bim/module/model/window.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import math import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 6bf9b0ac2a..7215a1bb2d 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -1,5 +1,25 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy +import blenderbim.bim.module.type.prop as type_prop from bpy.types import WorkSpaceTool from blenderbim.bim.ifc import IfcStore @@ -17,7 +37,7 @@ class BimTool(WorkSpaceTool): bl_keymap = ( # ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}), # ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}), - ("bim.add_type_instance", {"type": "A", "value": "PRESS", "shift": True}, {"properties": []}), + ("bim.hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}), ("bim.hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}), ("bim.join_wall", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}), ("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}), @@ -33,9 +53,20 @@ class BimTool(WorkSpaceTool): def draw_settings(context, layout, tool): row = layout.row(align=True) + if not IfcStore.get_file(): + row.label(text="No IFC Project", icon="ERROR") + return props = context.scene.BIMTypeProperties - row.prop(props, "ifc_class", text="") - row.prop(props, "relating_type", text="") + ifc_classes_is_empty = not bool(type_prop.getIfcTypes(props, context)) + if ifc_classes_is_empty: + row.label(text="No IFC Class") + else: + row.prop(props, "ifc_class", text="") + if type_prop.getAvailableTypes(props, context): + row.prop(props, "relating_type", text="") + else: + row.label(text="No Relating Type") + row.label(text="", icon="BLANK1") @@ -43,34 +74,35 @@ class BimTool(WorkSpaceTool): row.label(text="", icon="EVENT_SHIFT") row.label(text="Add Type Instance", icon="EVENT_A") - if props.ifc_class == "IfcWallType": - row = layout.row() - row.label(text="Join") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Extend", icon="EVENT_E") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Butt", icon="EVENT_T") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Mitre", icon="EVENT_Y") + if not ifc_classes_is_empty: + if props.ifc_class == "IfcWallType": + row = layout.row() + row.label(text="Join") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Extend", icon="EVENT_E") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Butt", icon="EVENT_T") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Mitre", icon="EVENT_Y") - row = layout.row() - row.label(text="Wall Tools") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Flip", icon="EVENT_F") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Split", icon="EVENT_S") + row = layout.row() + row.label(text="Wall Tools") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Flip", icon="EVENT_F") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Split", icon="EVENT_S") - if props.ifc_class in ["IfcColumnType", "IfcBeamType", "IfcMemberType"]: - row = layout.row() - row.label(text="Join") - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="Extend", icon="EVENT_E") + if props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"): + row = layout.row() + row.label(text="Join") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="Extend", icon="EVENT_E") row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") @@ -105,40 +137,51 @@ class Hotkey(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} hotkey: bpy.props.StringProperty() + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): self.props = context.scene.BIMTypeProperties + self.ifc_classes_is_empty = not bool(type_prop.getIfcTypes(self.props, context)) getattr(self, f"hotkey_{self.hotkey}")() return {"FINISHED"} + def hotkey_S_A(self): + bpy.ops.bim.add_type_instance() + def hotkey_S_C(self): - if self.props.ifc_class == "IfcWallType": + if not self.ifc_classes_is_empty and self.props.ifc_class == "IfcWallType": bpy.ops.bim.align_wall(align_type="CENTERLINE") else: bpy.ops.bim.align_product(align_type="CENTERLINE") def hotkey_S_E(self): + if self.ifc_classes_is_empty: + return if self.props.ifc_class == "IfcWallType": bpy.ops.bim.join_wall(join_type="T") elif self.props.ifc_class in ["IfcColumnType", "IfcBeamType", "IfcMemberType"]: bpy.ops.bim.extend_profile() def hotkey_S_V(self): - if self.props.ifc_class == "IfcWallType": + if not self.ifc_classes_is_empty and self.props.ifc_class == "IfcWallType": bpy.ops.bim.align_wall(align_type="INTERIOR") else: bpy.ops.bim.align_product(align_type="POSITIVE") def hotkey_S_X(self): - if self.props.ifc_class == "IfcWallType": - bpy.ops.bim.align_wall(align_type="EXTERIOR") + if not self.ifc_classes_is_empty and self.props.ifc_class == "IfcWallType": + if bpy.ops.bim.align_wall.poll(): + bpy.ops.bim.align_wall(align_type="EXTERIOR") else: bpy.ops.bim.align_product(align_type="NEGATIVE") def hotkey_S_O(self): - bpy.ops.bim.add_element_opening() + bpy.ops.bim.add_element_opening(voided_building_element="", filling_building_element="") def hotkey_A_D(self): bpy.ops.bim.toggle_decomposition_parenting() diff --git a/src/blenderbim/blenderbim/bim/module/owner/__init__.py b/src/blenderbim/blenderbim/bim/module/owner/__init__.py index 592e0e0167..b60dc2c370 100644 --- a/src/blenderbim/blenderbim/bim/module/owner/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/owner/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/owner/operator.py b/src/blenderbim/blenderbim/bim/module/owner/operator.py index 744822911a..50cb544dd3 100644 --- a/src/blenderbim/blenderbim/bim/module/owner/operator.py +++ b/src/blenderbim/blenderbim/bim/module/owner/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/owner/prop.py b/src/blenderbim/blenderbim/bim/module/owner/prop.py index 367aa13784..9629575be1 100644 --- a/src/blenderbim/blenderbim/bim/module/owner/prop.py +++ b/src/blenderbim/blenderbim/bim/module/owner/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/owner/ui.py b/src/blenderbim/blenderbim/bim/module/owner/ui.py index 42c91c5603..e451c3af2c 100644 --- a/src/blenderbim/blenderbim/bim/module/owner/ui.py +++ b/src/blenderbim/blenderbim/bim/module/owner/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel from ifcopenshell.api.owner.data import Data @@ -45,7 +64,7 @@ def draw_roles_ui(box, assigned_object_id, roles, context): box2 = box.box() row = draw_prop_on_new_row(box2, blender_role, "name", align=True, icon="MOD_CLOTH", text="") row.operator("bim.edit_role", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_role", icon="X", text="") + row.operator("bim.disable_editing_role", icon="CANCEL", text="") if blender_role.name == "USERDEFINED": draw_prop_on_new_row(box2, blender_role, "user_defined_role") draw_prop_on_new_row(box2, blender_role, "description") @@ -73,7 +92,7 @@ def draw_addresses_ui(box, assigned_object_id, addresses, file, context): box2 = box.box() row = draw_prop_on_new_row(box2, blender_address, "purpose", align=True, icon="MOD_CLOTH", text="") row.operator("bim.edit_address", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_address", icon="X", text="") + row.operator("bim.disable_editing_address", icon="CANCEL", text="") if blender_address.purpose == "USERDEFINED": draw_prop_on_new_row(box2, blender_address, "user_defined_purpose") draw_prop_on_new_row(box2, blender_address, "description") @@ -131,7 +150,7 @@ class BIM_PT_people(Panel): box = self.layout.box() row = draw_prop_on_new_row(box, blender_person, "name", align=True, icon="USER", text="") row.operator("bim.edit_person", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_person", icon="X", text="") + row.operator("bim.disable_editing_person", icon="CANCEL", text="") draw_prop_on_new_row(box, blender_person, "family_name") draw_prop_on_new_row(box, blender_person, "given_name") draw_string_collection(box, blender_person, "middle_names") @@ -185,7 +204,7 @@ class BIM_PT_organisations(Panel): row = box.row(align=True) row.prop(blender_organisation, "name", icon="USER", text="") row.operator("bim.edit_organisation", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_organisation", icon="X", text="") + row.operator("bim.disable_editing_organisation", icon="CANCEL", text="") draw_prop_on_new_row(box, blender_organisation, "identification") draw_prop_on_new_row(box, blender_organisation, "description") diff --git a/src/blenderbim/blenderbim/bim/module/patch/__init__.py b/src/blenderbim/blenderbim/bim/module/patch/__init__.py index d8a39535d2..12aec24743 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/patch/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator @@ -5,6 +24,7 @@ classes = ( operator.SelectIfcPatchInput, operator.SelectIfcPatchOutput, operator.ExecuteIfcPatch, + operator.UpdateIfcPatchArguments, prop.BIMPatchProperties, ui.BIM_PT_patch, ) diff --git a/src/blenderbim/blenderbim/bim/module/patch/operator.py b/src/blenderbim/blenderbim/bim/module/patch/operator.py index 5015942931..ea76cd51c3 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/operator.py +++ b/src/blenderbim/blenderbim/bim/module/patch/operator.py @@ -1,7 +1,31 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json +try: + import ifcpatch +except: + print("IfcPatch not available") + class SelectIfcPatchInput(bpy.types.Operator): bl_idname = "bim.select_ifc_patch_input" @@ -39,6 +63,7 @@ class ExecuteIfcPatch(bpy.types.Operator): bl_idname = "bim.execute_ifc_patch" bl_label = "Execute IFCPatch" file_format: bpy.props.StringProperty() + use_json_for_args: bpy.props.BoolProperty() @classmethod def poll(cls, context): @@ -46,15 +71,47 @@ class ExecuteIfcPatch(bpy.types.Operator): return os.path.isfile(input_file) and "ifc" in os.path.splitext(input_file)[1] def execute(self, context): - import ifcpatch + props = context.scene.BIMPatchProperties + if self.use_json_for_args or not props.ifc_patch_args_attr: + arguments = json.loads(props.ifc_patch_args or "[]") + else: + arguments = [arg.get_value() for arg in props.ifc_patch_args_attr] ifcpatch.execute( { - "input": context.scene.BIMPatchProperties.ifc_patch_input, - "output": context.scene.BIMPatchProperties.ifc_patch_output, - "recipe": context.scene.BIMPatchProperties.ifc_patch_recipes, - "arguments": json.loads(context.scene.BIMPatchProperties.ifc_patch_args or "[]"), + "input": props.ifc_patch_input, + "output": props.ifc_patch_output, + "recipe": props.ifc_patch_recipes, + "arguments": arguments, "log": os.path.join(context.scene.BIMProperties.data_dir, "process.log"), } ) return {"FINISHED"} + + +class UpdateIfcPatchArguments(bpy.types.Operator): + bl_idname = "bim.update_ifc_patch_arguments" + bl_label = "Update IFC Patch arguments" + recipe: bpy.props.StringProperty() + + def execute(self, context): + if self.recipe == "": + print("No Recipe Selected. Impossible to load arguments") + return {"FINISHED"} + patch_args = context.scene.BIMPatchProperties.ifc_patch_args_attr + patch_args.clear() + docs = ifcpatch.extract_docs(self.recipe, "Patcher", "__init__", ("src", "file", "logger", "args")) + if docs and "inputs" in docs: + inputs = docs["inputs"] + for arg_name in inputs: + arg_info = inputs[arg_name] + new_attr = patch_args.add() + new_attr.data_type = { + "str": "string", + "float": "float", + "int": "integer", + "bool": "boolean", + }[arg_info.get("type", "str")] + new_attr.name = arg_name + new_attr.set_value(arg_info.get("default", new_attr.get_value_default())) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/patch/prop.py b/src/blenderbim/blenderbim/bim/module/patch/prop.py index bfee66f4b0..ac9e09faa9 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/prop.py +++ b/src/blenderbim/blenderbim/bim/module/patch/prop.py @@ -1,6 +1,26 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import importlib from pathlib import Path +import ifcpatch from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup from bpy.props import ( @@ -32,12 +52,17 @@ def getIfcPatchRecipes(self, context): f = str(filename.stem) if f == "__init__": continue - ifcpatchrecipes_enum.append((f, f, "")) + docs = ifcpatch.extract_docs(f, "Patcher", "__init__", ("src", "file", "logger", "args")) + ifcpatchrecipes_enum.append((f, f, docs.get("description","") if docs else "")) return ifcpatchrecipes_enum +def update_ifc_patch_recipe(self, context): + bpy.ops.bim.update_ifc_patch_arguments(recipe = self.ifc_patch_recipes) + class BIMPatchProperties(PropertyGroup): - ifc_patch_recipes: EnumProperty(items=getIfcPatchRecipes, name="Recipes") + ifc_patch_recipes: EnumProperty(items=getIfcPatchRecipes, name="Recipes", update=update_ifc_patch_recipe) ifc_patch_input: StringProperty(default="", name="IFC Patch Input IFC") ifc_patch_output: StringProperty(default="", name="IFC Patch Output IFC") ifc_patch_args: StringProperty(default="", name="Arguments") + ifc_patch_args_attr: CollectionProperty(type=Attribute, name="Arguments") diff --git a/src/blenderbim/blenderbim/bim/module/patch/ui.py b/src/blenderbim/blenderbim/bim/module/patch/ui.py index 49600d2d1c..1617adbb27 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/ui.py +++ b/src/blenderbim/blenderbim/bim/module/patch/ui.py @@ -1,8 +1,27 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy -from bpy.types import Panel +from blenderbim.bim.helper import draw_attributes -class BIM_PT_patch(Panel): +class BIM_PT_patch(bpy.types.Panel): bl_label = "IFC Patch" bl_idname = "BIM_PT_patch" bl_options = {"DEFAULT_CLOSED"} @@ -13,20 +32,25 @@ class BIM_PT_patch(Panel): def draw(self, context): layout = self.layout layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene props = scene.BIMPatchProperties - row = layout.row() - row.prop(props, "ifc_patch_recipes") + row.prop(props, "ifc_patch_recipes") + + row = layout.row(align=True) row.prop(props, "ifc_patch_input") row.operator("bim.select_ifc_patch_input", icon="FILE_FOLDER", text="") + row = layout.row(align=True) row.prop(props, "ifc_patch_output") row.operator("bim.select_ifc_patch_output", icon="FILE_FOLDER", text="") - row = layout.row() - row.prop(props, "ifc_patch_args") - row = layout.row() - op = row.operator("bim.execute_ifc_patch") + if props.ifc_patch_args_attr: + draw_attributes(props.ifc_patch_args_attr, layout) + else: + layout.row().prop(props, "ifc_patch_args") + op = layout.operator("bim.execute_ifc_patch") + op.use_json_for_args = len(props.ifc_patch_args_attr) == 0 diff --git a/src/blenderbim/blenderbim/bim/module/profile/__init__.py b/src/blenderbim/blenderbim/bim/module/profile/__init__.py index 8b4d495a80..60e3baa2c2 100644 --- a/src/blenderbim/blenderbim/bim/module/profile/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/profile/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/profile/operator.py b/src/blenderbim/blenderbim/bim/module/profile/operator.py index c5999173f4..f94f13bfb0 100644 --- a/src/blenderbim/blenderbim/bim/module/profile/operator.py +++ b/src/blenderbim/blenderbim/bim/module/profile/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api import blenderbim.bim.helper @@ -12,8 +31,7 @@ class LoadProfiles(bpy.types.Operator): def execute(self, context): props = context.scene.BIMProfileProperties - while len(props.profiles) > 0: - props.profiles.remove(0) + props.profiles.clear() for ifc_definition_id, profile in Data.profiles.items(): new = props.profiles.add() @@ -61,8 +79,7 @@ class EnableEditingProfile(bpy.types.Operator): def execute(self, context): props = context.scene.BIMProfileProperties - while len(props.profile_attributes) > 0: - props.profile_attributes.remove(0) + props.profile_attributes.clear() data = Data.profiles[self.profile] diff --git a/src/blenderbim/blenderbim/bim/module/profile/prop.py b/src/blenderbim/blenderbim/bim/module/profile/prop.py index b2392e8b06..868093f64a 100644 --- a/src/blenderbim/blenderbim/bim/module/profile/prop.py +++ b/src/blenderbim/blenderbim/bim/module/profile/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell import ifcopenshell.util.schema diff --git a/src/blenderbim/blenderbim/bim/module/profile/ui.py b/src/blenderbim/blenderbim/bim/module/profile/ui.py index 3a0dcec9a7..3d81fce607 100644 --- a/src/blenderbim/blenderbim/bim/module/profile/ui.py +++ b/src/blenderbim/blenderbim/bim/module/profile/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/project/__init__.py b/src/blenderbim/blenderbim/bim/module/project/__init__.py index c01b78d775..e05b1c8294 100644 --- a/src/blenderbim/blenderbim/bim/module/project/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/project/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index f47e94d8ac..600364a524 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import logging import ifcopenshell @@ -24,6 +43,7 @@ class CreateProject(bpy.types.Operator): return result def _execute(self, context): + active_object = context.view_layer.objects.active self.file = IfcStore.get_file() if self.file: return {"FINISHED"} @@ -60,6 +80,7 @@ class CreateProject(bpy.types.Operator): bpy.ops.bim.assign_object(related_object=building.name, relating_object=site.name) bpy.ops.bim.assign_object(related_object=building_storey.name, relating_object=building.name) + context.view_layer.objects.active = active_object return {"FINISHED"} def get_name(self, ifc_class, name): @@ -163,16 +184,13 @@ class RefreshLibrary(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMProjectProperties - while len(self.props.library_elements) > 0: - self.props.library_elements.remove(0) - - while len(self.props.library_breadcrumb) > 0: - self.props.library_breadcrumb.remove(0) + self.props.library_elements.clear() + self.props.library_breadcrumb.clear() self.props.active_library_element = "" types = IfcStore.library_file.wrapped_data.types_with_super() - for importable_type in ["IfcTypeProduct", "IfcMaterial", "IfcCostSchedule", "IfcProfileDef"]: + for importable_type in sorted(["IfcTypeProduct", "IfcMaterial", "IfcCostSchedule", "IfcProfileDef"]): if importable_type in types: new = self.props.library_elements.add() new.name = importable_type @@ -193,16 +211,13 @@ class ChangeLibraryElement(bpy.types.Operator): crumb.name = self.element_name elements = IfcStore.library_file.by_type(self.element_name) [ifc_classes.add(e.is_a()) for e in elements] - while len(self.props.library_elements) > 0: - self.props.library_elements.remove(0) + self.props.library_elements.clear() if len(ifc_classes) == 1 and list(ifc_classes)[0] == self.element_name: - for element in elements: + for name, ifc_definition_id in sorted([(self.get_name(e), e.id()) for e in elements]): new = self.props.library_elements.add() - if element.is_a("IfcProfileDef"): - new.name = element.ProfileName or "Unnamed" - else: - new.name = element.Name or "Unnamed" - new.ifc_definition_id = element.id() + new.name = name + new.ifc_definition_id = ifc_definition_id + element = IfcStore.library_file.by_id(ifc_definition_id) if IfcStore.library_file.schema == "IFC2X3" or not IfcStore.library_file.by_type("IfcProjectLibrary"): new.is_declared = False elif getattr(element, "HasContext", None) and element.HasContext[0].RelatingContext.is_a( @@ -210,11 +225,16 @@ class ChangeLibraryElement(bpy.types.Operator): ): new.is_declared = True else: - for ifc_class in ifc_classes: + for ifc_class in sorted(ifc_classes): new = self.props.library_elements.add() new.name = ifc_class return {"FINISHED"} + def get_name(self, element): + if element.is_a("IfcProfileDef"): + return element.ProfileName or "Unnamed" + return element.Name or "Unnamed" + class RewindLibrary(bpy.types.Operator): bl_idname = "bim.rewind_library" @@ -321,6 +341,10 @@ class AppendLibraryElement(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} definition: bpy.props.IntProperty() + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): return IfcStore.execute_ifc_operator(self, context) @@ -358,9 +382,10 @@ class AppendLibraryElement(bpy.types.Operator): type_collection = bpy.data.collections.get("Types") if not type_collection: type_collection = bpy.data.collections.new("Types") - for collection in bpy.data.collections: + for collection in bpy.context.view_layer.layer_collection.children: if "IfcProject/" in collection.name: - collection.children.link(type_collection) + collection.collection.children.link(type_collection) + collection.children["Types"].hide_viewport = True break ifc_importer = import_ifc.IfcImporter(ifc_import_settings) @@ -403,6 +428,10 @@ class EnableEditingHeader(bpy.types.Operator): bl_label = "Enable Editing Header" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMProjectProperties @@ -435,6 +464,10 @@ class EditHeader(bpy.types.Operator): bl_label = "Edit Header" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return IfcStore.get_file() + def execute(self, context): IfcStore.begin_transaction(self) self.transaction_data = {} diff --git a/src/blenderbim/blenderbim/bim/module/project/prop.py b/src/blenderbim/blenderbim/bim/module/project/prop.py index a4052984a9..4a263dc3eb 100644 --- a/src/blenderbim/blenderbim/bim/module/project/prop.py +++ b/src/blenderbim/blenderbim/bim/module/project/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index 435ff66d9a..75198cb957 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/pset/__init__.py b/src/blenderbim/blenderbim/bim/module/pset/__init__.py index ad512786a3..ace6e1253f 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/pset/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator @@ -15,12 +34,14 @@ classes = ( prop.TaskPsetProperties, prop.ResourcePsetProperties, prop.ProfilePsetProperties, + prop.WorkSchedulePsetProperties, ui.BIM_PT_object_psets, ui.BIM_PT_object_qtos, ui.BIM_PT_material_psets, ui.BIM_PT_task_qtos, ui.BIM_PT_resource_qtos, ui.BIM_PT_profile_psets, + ui.BIM_PT_work_schedule_psets, ) @@ -30,6 +51,7 @@ def register(): bpy.types.Scene.TaskPsetProperties = bpy.props.PointerProperty(type=prop.TaskPsetProperties) bpy.types.Scene.ResourcePsetProperties = bpy.props.PointerProperty(type=prop.ResourcePsetProperties) bpy.types.Scene.ProfilePsetProperties = bpy.props.PointerProperty(type=prop.ProfilePsetProperties) + bpy.types.Scene.WorkSchedulePsetProperties = bpy.props.PointerProperty(type=prop.WorkSchedulePsetProperties) def unregister(): @@ -38,3 +60,4 @@ def unregister(): del bpy.types.Scene.TaskPsetProperties del bpy.types.Scene.ResourcePsetProperties del bpy.types.Scene.ProfilePsetProperties + del bpy.types.Scene.WorkSchedulePsetProperties diff --git a/src/blenderbim/blenderbim/bim/module/pset/operator.py b/src/blenderbim/blenderbim/bim/module/pset/operator.py index 071d5dab3b..3e6a6edf82 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -24,6 +43,8 @@ def get_pset_props(context, obj, obj_type): return context.scene.ResourcePsetProperties elif obj_type == "Profile": return context.scene.ProfilePsetProperties + elif obj_type == "WorkSchedule": + return context.scene.WorkSchedulePsetProperties def get_pset_obj_ifc_definition_id(context, obj, obj_type): @@ -45,7 +66,8 @@ def get_pset_obj_ifc_definition_id(context, obj, obj_type): return context.scene.BIMProfileProperties.profiles[ context.scene.BIMProfileProperties.active_profile_index ].ifc_definition_id - + elif obj_type == "WorkSchedule": + return context.scene.BIMWorkScheduleProperties.active_work_schedule_id class TogglePsetExpansion(bpy.types.Operator): @@ -71,8 +93,7 @@ class EnablePsetEditing(bpy.types.Operator): def execute(self, context): self.props = get_pset_props(context, self.obj, self.obj_type) - while len(self.props.properties) > 0: - self.props.properties.remove(0) + self.props.properties.clear() data = Data.psets if self.pset_id in Data.psets else Data.qtos pset_data = data[self.pset_id] @@ -100,8 +121,9 @@ class EnablePsetEditing(bpy.types.Operator): IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel") ) except: - # TODO: Occurs if the data type is something that exists in IFC4 and not in IFC2X3. To fully fix - # this we need to generate the IFC2X3 pset template definitions. + # TODO: Occurs if the data type is something that exists in + # IFC4 and not in IFC2X3. To fully fix this we need to + # generate the IFC2X3 pset template definitions. continue elif prop_template.TemplateType == "P_ENUMERATEDVALUE": data_type = "enum" @@ -116,6 +138,7 @@ class EnablePsetEditing(bpy.types.Operator): new = self.props.properties.add() new.name = prop_template.Name new.is_null = data.get(prop_template.Name, None) is None + new.is_optional = True new.data_type = data_type if data_type == "string": @@ -136,31 +159,12 @@ class EnablePsetEditing(bpy.types.Operator): prop = Data.properties[prop_id] value = prop["NominalValue"] - if isinstance(value, str): - data_type = "string" - elif isinstance(value, float): - data_type = "float" - elif isinstance(value, bool): - data_type = "boolean" - elif isinstance(value, int): - data_type = "integer" - else: - data_type = "string" - value = str(value) - new = self.props.properties.add() + new.set_value(value) new.name = prop["Name"] - new.is_null = prop["NominalValue"] is None - new.data_type = data_type - - if data_type == "string": - new.string_value = "" if new.is_null else value - elif data_type == "integer": - new.int_value = 0 if new.is_null else value - elif data_type == "float": - new.float_value = 0.0 if new.is_null else value - elif data_type == "boolean": - new.bool_value = False if new.is_null else value + new.is_null = value is None + new.is_optional = True + new.set_value(new.get_value_default() if new.is_null else value) class DisablePsetEditing(bpy.types.Operator): @@ -200,18 +204,7 @@ class EditPset(bpy.types.Operator): else: data = Data.psets if pset_id in Data.psets else Data.qtos for prop in props.properties: - if prop.is_null: - properties[prop.name] = None - elif prop.data_type == "string": - properties[prop.name] = prop.string_value - elif prop.data_type == "boolean": - properties[prop.name] = prop.bool_value - elif prop.data_type == "integer": - properties[prop.name] = prop.int_value - elif prop.data_type == "float": - properties[prop.name] = prop.float_value - elif prop.data_type == "enum": - properties[prop.name] = prop.enum_value + properties[prop.name] = prop.get_value() if pset_id in Data.psets: ifcopenshell.api.run( diff --git a/src/blenderbim/blenderbim/bim/module/pset/prop.py b/src/blenderbim/blenderbim/bim/module/pset/prop.py index 2b9a255971..ee2c1c4f4a 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/prop.py +++ b/src/blenderbim/blenderbim/bim/module/pset/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import blenderbim.bim.schema from blenderbim.bim.prop import Attribute @@ -82,6 +101,15 @@ def getProfilePsetNames(self, context): return psetnames[ifc_class] +def getWorkSchedulePsetNames(self, context): + global psetnames + ifc_class = "IfcWorkSchedule" + if ifc_class not in psetnames: + psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) + psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] + return psetnames[ifc_class] + + def getQtoNames(self, context): global qtonames if "/" in context.active_object.name: @@ -127,3 +155,10 @@ class ProfilePsetProperties(PropertyGroup): active_pset_name: StringProperty(name="Pset Name") properties: CollectionProperty(name="Properties", type=Attribute) pset_name: EnumProperty(items=getProfilePsetNames, name="Pset Name") + + +class WorkSchedulePsetProperties(PropertyGroup): + active_pset_id: IntProperty(name="Active Pset ID") + active_pset_name: StringProperty(name="Pset Name") + properties: CollectionProperty(name="Properties", type=Attribute) + pset_name: EnumProperty(items=getWorkSchedulePsetNames, name="Pset Name") diff --git a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py index b1a056caeb..4e2469d0f6 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from mathutils import Vector diff --git a/src/blenderbim/blenderbim/bim/module/pset/ui.py b/src/blenderbim/blenderbim/bim/module/pset/ui.py index 4bed5d65dc..5b6b2b5a32 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset/ui.py @@ -1,6 +1,26 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel from ifcopenshell.api.pset.data import Data from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attribute def get_active_pset_obj_name(context, obj_type): @@ -68,17 +88,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type): def draw_psetqto_editable_ui(box, props, prop): row = box.row(align=True) - if prop.data_type == "string": - row.prop(prop, "string_value", text=prop.name) - elif prop.data_type == "integer": - row.prop(prop, "int_value", text=prop.name) - elif prop.data_type == "float": - row.prop(prop, "float_value", text=prop.name) - elif prop.data_type == "boolean": - row.prop(prop, "bool_value", text=prop.name) - elif prop.data_type == "enum": - row.prop(prop, "enum_value", text=prop.name) - row.prop(prop, "is_null", icon="RADIOBUT_OFF" if prop.is_null else "RADIOBUT_ON", text="") + draw_attribute(prop, row) if ( "length" in prop.name.lower() or "width" in prop.name.lower() @@ -197,7 +207,8 @@ class BIM_PT_material_psets(Panel): props = context.active_object.active_material.BIMObjectProperties if not props.ifc_definition_id: return False - if IfcStore.get_file().schema == "IFC2X3": + file = IfcStore.get_file() + if not file or file.schema == "IFC2X3": return False # We don't support material psets in IFC2X3 because they suck if props.ifc_definition_id not in Data.products: Data.load(IfcStore.get_file(), props.ifc_definition_id) @@ -321,3 +332,33 @@ class BIM_PT_profile_psets(Panel): psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[ifc_definition_id]["psets"]] for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]): draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Profile") + + +class BIM_PT_work_schedule_psets(Panel): + bl_label = "IFC Work Schedule Property Sets" + bl_idname = "BIM_PT_work_schedule_psets" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_work_schedules" + + @classmethod + def poll(cls, context): + props = context.scene.BIMWorkScheduleProperties + if not context.scene.BIMWorkScheduleProperties.active_work_schedule_id: + return False + return True + + def draw(self, context): + props = context.scene.WorkSchedulePsetProperties + ifc_definition_id = context.scene.BIMWorkScheduleProperties.active_work_schedule_id + if ifc_definition_id not in Data.products: + Data.load(IfcStore.get_file(), ifc_definition_id) + row = self.layout.row(align=True) + row.prop(props, "pset_name", text="") + op = row.operator("bim.add_pset", icon="ADD", text="") + op.obj_type = "WorkSchedule" + + psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[ifc_definition_id]["psets"]] + for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]): + draw_psetqto_ui(context, pset_id, pset, props, self.layout, "WorkSchedule") diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py b/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py index e62901c133..4094532ac0 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/operator.py b/src/blenderbim/blenderbim/bim/module/pset_template/operator.py index 452470240c..496ab64aac 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell import ifcopenshell.api diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py index 83b134c399..dae0f8d77f 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py index b252e4e496..0080ebb877 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel from blenderbim.bim.ifc import IfcStore @@ -29,7 +48,7 @@ class BIM_PT_pset_template(Panel): if props.active_pset_template_id: row.operator("bim.edit_pset_template", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_pset_template", text="", icon="X") + row.operator("bim.disable_editing_pset_template", text="", icon="CANCEL") else: row.operator("bim.add_pset_template", text="", icon="ADD") row.operator("bim.enable_editing_pset_template", text="", icon="GREASEPENCIL") @@ -78,7 +97,7 @@ class BIM_PT_pset_template(Panel): if props.active_prop_template_id and props.active_prop_template_id == prop_template_id: op = row.operator("bim.edit_prop_template", icon="CHECKMARK", text="") - row.operator("bim.disable_editing_prop_template", icon="X", text="") + row.operator("bim.disable_editing_prop_template", icon="CANCEL", text="") elif props.active_prop_template_id and props.active_prop_template_id != prop_template_id: row.operator("bim.remove_prop_template", icon="X", text="").prop_template = prop_template_id else: diff --git a/src/blenderbim/blenderbim/bim/module/qto/__init__.py b/src/blenderbim/blenderbim/bim/module/qto/__init__.py index 2cd6381ffb..c99f657c4e 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/qto/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/qto/helper.py b/src/blenderbim/blenderbim/bim/module/qto/helper.py index 56ff71b73a..8826a8d5b7 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/helper.py +++ b/src/blenderbim/blenderbim/bim/module/qto/helper.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import bmesh @@ -6,12 +25,38 @@ def calculate_height(obj): return obj.dimensions[2] -def calculate_volume(obj): - bm = bmesh.new() - bm.from_mesh(obj.data) - result = bm.calc_volume() - bm.free() - return result +def calculate_edges_lengths(objs, context): + return calculate_mesh_quantity(objs, context, lambda bm: sum((e.calc_length() for e in bm.edges if e.select))) + + +def calculate_faces_areas(objs, context): + return calculate_mesh_quantity(objs, context, lambda bm: sum((f.calc_area() for f in bm.faces if f.select))) + + +def calculate_volumes(objs, context): + return calculate_mesh_quantity(objs, context, lambda bm: bm.calc_volume()) + + +def calculate_mesh_quantity(objs: bpy.types.Object, context, operation): + """Get the sum of the target quantity on all passed mesh objects + + :param objs: iterable of mesh object + :param context: current execution context + :param operation: function which takes a single bmesh as an argument, returns a float value + :returns float: + """ + result = 0 + edit_mode = context.active_object.mode == "EDIT" + for obj in objs: + if edit_mode: + bm = bmesh.from_edit_mesh(obj.data) + result += operation(bm) + else: + bm = bmesh.new() + bm.from_mesh(obj.data) + result += operation(bm) + bm.free() + return result def calculate_formwork_area(objs, context): @@ -30,10 +75,11 @@ def calculate_formwork_area(objs, context): context.collection.objects.link(new_obj) copied_objs.append(new_obj) - context_override = {} - context_override["object"] = context_override["active_object"] = copied_objs[0] - context_override["selected_objects"] = context_override["selected_editable_objects"] = copied_objs - bpy.ops.object.join(context_override) + if len(objs) > 1: + context_override = {} + context_override["object"] = context_override["active_object"] = copied_objs[0] + context_override["selected_objects"] = context_override["selected_editable_objects"] = copied_objs + bpy.ops.object.join(context_override) copied_objs[0].name = "Formwork" copied_objs[0].BIMObjectProperties.ifc_definition_id = 0 diff --git a/src/blenderbim/blenderbim/bim/module/qto/operator.py b/src/blenderbim/blenderbim/bim/module/qto/operator.py index ef6b12268c..de4b968764 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/operator.py +++ b/src/blenderbim/blenderbim/bim/module/qto/operator.py @@ -1,5 +1,23 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy -import bmesh import ifcopenshell import ifcopenshell.api from blenderbim.bim.ifc import IfcStore @@ -12,14 +30,12 @@ class CalculateEdgeLengths(bpy.types.Operator): bl_label = "Calculate Edge Lengths" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects and context.active_object + def execute(self, context): - result = 0 - for obj in context.selected_objects: - if not obj.data or not obj.data.edges: - continue - for edge in obj.data.edges: - if edge.select: - result += (obj.data.vertices[edge.vertices[1]].co - obj.data.vertices[edge.vertices[0]].co).length + result = helper.calculate_edges_lengths([o for o in context.selected_objects if o.type == "MESH"], context) context.scene.BIMQtoProperties.qto_result = str(round(result, 3)) return {"FINISHED"} @@ -29,14 +45,12 @@ class CalculateFaceAreas(bpy.types.Operator): bl_label = "Calculate Face Areas" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects and context.active_object + def execute(self, context): - result = 0 - for obj in context.selected_objects: - if not obj.data or not obj.data.polygons: - continue - for polygon in obj.data.polygons: - if polygon.select: - result += polygon.area + result = helper.calculate_faces_areas([o for o in context.selected_objects if o.type == "MESH"], context) context.scene.BIMQtoProperties.qto_result = str(round(result, 3)) return {"FINISHED"} @@ -46,15 +60,12 @@ class CalculateObjectVolumes(bpy.types.Operator): bl_label = "Calculate Object Volumes" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects and context.active_object + def execute(self, context): - result = 0 - for obj in context.selected_objects: - if not obj.data or not isinstance(obj.data, bpy.types.Mesh): - continue - bm = bmesh.new() - bm.from_mesh(obj.data) - result += bm.calc_volume() - bm.free() + result = helper.calculate_volumes([o for o in context.selected_objects if o.type == "MESH"], context) context.scene.BIMQtoProperties.qto_result = str(round(result, 3)) return {"FINISHED"} @@ -64,17 +75,21 @@ class ExecuteQtoMethod(bpy.types.Operator): bl_label = "Execute Qto Method" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): + selected_mesh_objects = [o for o in context.selected_objects if o.type == "MESH"] props = context.scene.BIMQtoProperties result = 0 if props.qto_methods == "HEIGHT": - for obj in context.selected_objects: + for obj in selected_mesh_objects: result += helper.calculate_height(obj) elif props.qto_methods == "VOLUME": - for obj in context.selected_objects: - result += helper.calculate_volume(obj) + result = helper.calculate_volumes(selected_mesh_objects, context) elif props.qto_methods == "FORMWORK": - result = helper.calculate_formwork_area(context.selected_objects, context) + result = helper.calculate_formwork_area(selected_mesh_objects, context) props.qto_result = str(round(result, 3)) return {"FINISHED"} @@ -84,20 +99,24 @@ class QuantifyObjects(bpy.types.Operator): bl_label = "Quantify Objects" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return IfcStore.get_file() and context.selected_objects + def execute(self, context): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): props = context.scene.BIMQtoProperties self.file = IfcStore.get_file() - for obj in context.selected_objects: + for obj in (o for o in context.selected_objects if o.type == "MESH"): if not obj.BIMObjectProperties.ifc_definition_id: continue result = 0 if props.qto_methods == "HEIGHT": result = helper.calculate_height(obj) elif props.qto_methods == "VOLUME": - result = helper.calculate_volume(obj) + result = helper.calculate_volumes([obj], context) elif props.qto_methods == "FORMWORK": result = helper.calculate_formwork_area([obj], context) if not result: diff --git a/src/blenderbim/blenderbim/bim/module/qto/prop.py b/src/blenderbim/blenderbim/bim/module/qto/prop.py index a081e0cb54..4fec6fec26 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/prop.py +++ b/src/blenderbim/blenderbim/bim/module/qto/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/qto/ui.py b/src/blenderbim/blenderbim/bim/module/qto/ui.py index 9bdcbb8147..aea862d0ce 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/ui.py +++ b/src/blenderbim/blenderbim/bim/module/qto/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel diff --git a/src/blenderbim/blenderbim/bim/module/resource/__init__.py b/src/blenderbim/blenderbim/bim/module/resource/__init__.py index c401265b4d..8794902494 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/resource/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/resource/operator.py b/src/blenderbim/blenderbim/bim/module/resource/operator.py index 2150b39182..34b70a80f4 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/operator.py +++ b/src/blenderbim/blenderbim/bim/module/resource/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell.api @@ -18,8 +37,7 @@ class LoadResources(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMResourceProperties self.tprops = context.scene.BIMResourceTreeProperties - while len(self.tprops.resources) > 0: - self.tprops.resources.remove(0) + self.tprops.resources.clear() self.contracted_resources = json.loads(self.props.contracted_resources) for resource_id, data in Data.resources.items(): @@ -53,8 +71,7 @@ class EnableEditingResource(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMResourceProperties self.props.active_resource_id = self.resource - while len(self.props.resource_attributes) > 0: - self.props.resource_attributes.remove(0) + self.props.resource_attributes.clear() self.props.editing_resource_type = "ATTRIBUTES" self.enable_editing_resource() return {"FINISHED"} @@ -280,8 +297,7 @@ class EnableEditingResourceTime(bpy.types.Operator): props = context.scene.BIMResourceProperties self.file = IfcStore.get_file() resource_time_id = Data.resources[self.resource]["Usage"] or self.add_resource_time().id() - while len(props.resource_time_attributes) > 0: - props.resource_time_attributes.remove(0) + props.resource_time_attributes.clear() data = Data.resource_times[resource_time_id] diff --git a/src/blenderbim/blenderbim/bim/module/resource/prop.py b/src/blenderbim/blenderbim/bim/module/resource/prop.py index d7b285d372..5681deba24 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/prop.py +++ b/src/blenderbim/blenderbim/bim/module/resource/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/resource/ui.py b/src/blenderbim/blenderbim/bim/module/resource/ui.py index bb5c517202..c00d61bedf 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/ui.py +++ b/src/blenderbim/blenderbim/bim/module/resource/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.resource.data import Data diff --git a/src/blenderbim/blenderbim/bim/module/root/__init__.py b/src/blenderbim/blenderbim/bim/module/root/__init__.py index 0d41a5eba9..4c7c15696e 100644 --- a/src/blenderbim/blenderbim/bim/module/root/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/root/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index d3207eca2e..544357b7c4 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import numpy as np import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/root/prop.py b/src/blenderbim/blenderbim/bim/module/root/prop.py index b79a2a94ea..6a28a40b51 100644 --- a/src/blenderbim/blenderbim/bim/module/root/prop.py +++ b/src/blenderbim/blenderbim/bim/module/root/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell import ifcopenshell.util.schema @@ -53,7 +72,8 @@ def refreshPredefinedTypes(self, context): global types_enum types_enum.clear() enum = getIfcPredefinedTypes(self, context) - context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0] + if enum: + context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0] def getIfcProducts(self, context): diff --git a/src/blenderbim/blenderbim/bim/module/root/ui.py b/src/blenderbim/blenderbim/bim/module/root/ui.py index 6c92e39e26..aa2ea98ec2 100644 --- a/src/blenderbim/blenderbim/bim/module/root/ui.py +++ b/src/blenderbim/blenderbim/bim/module/root/ui.py @@ -1,4 +1,24 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy +import blenderbim.bim.module.root.prop as root_prop from bpy.types import Panel from ifcopenshell.api.root.data import Data from blenderbim.bim.ifc import IfcStore @@ -30,7 +50,9 @@ class BIM_PT_class(Panel): row = self.layout.row(align=True) row.operator("bim.reassign_class", icon="CHECKMARK") row.operator("bim.disable_reassign_class", icon="CANCEL", text="") - self.draw_class_dropdowns(context) + self.draw_class_dropdowns( + context, + root_prop.getIfcPredefinedTypes(context.scene.BIMRootProperties, context)) else: data = Data.products[props.ifc_definition_id] name = data["type"] @@ -53,23 +75,24 @@ class BIM_PT_class(Panel): else: row.operator("bim.unassign_class", icon="X", text="").obj = context.active_object.name else: - self.draw_class_dropdowns(context) + ifc_predefined_types = root_prop.getIfcPredefinedTypes(context.scene.BIMRootProperties, context) + self.draw_class_dropdowns(context, ifc_predefined_types) row = self.layout.row(align=True) op = row.operator("bim.assign_class") op.ifc_class = context.scene.BIMRootProperties.ifc_class - op.predefined_type = context.scene.BIMRootProperties.ifc_predefined_type + op.predefined_type = context.scene.BIMRootProperties.ifc_predefined_type if ifc_predefined_types else "" op.userdefined_type = context.scene.BIMRootProperties.ifc_userdefined_type - def draw_class_dropdowns(self, context): + def draw_class_dropdowns(self, context, ifc_predefined_types): props = context.scene.BIMRootProperties row = self.layout.row() row.prop(props, "ifc_product") row = self.layout.row() row.prop(props, "ifc_class") - if props.ifc_predefined_type: + if ifc_predefined_types: row = self.layout.row() row.prop(props, "ifc_predefined_type") - if props.ifc_predefined_type == "USERDEFINED": + if ifc_predefined_types == "USERDEFINED": row = self.layout.row() row.prop(props, "ifc_userdefined_type") row = self.layout.row() diff --git a/src/blenderbim/blenderbim/bim/module/search/__init__.py b/src/blenderbim/blenderbim/bim/module/search/__init__.py index 827083f847..d11e217190 100644 --- a/src/blenderbim/blenderbim/bim/module/search/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/search/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/search/operator.py b/src/blenderbim/blenderbim/bim/module/search/operator.py index 3b39499657..af4743877f 100644 --- a/src/blenderbim/blenderbim/bim/module/search/operator.py +++ b/src/blenderbim/blenderbim/bim/module/search/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import re import bpy import ifcopenshell diff --git a/src/blenderbim/blenderbim/bim/module/search/prop.py b/src/blenderbim/blenderbim/bim/module/search/prop.py index 7723434add..722d051314 100644 --- a/src/blenderbim/blenderbim/bim/module/search/prop.py +++ b/src/blenderbim/blenderbim/bim/module/search/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import PropertyGroup from bpy.props import ( diff --git a/src/blenderbim/blenderbim/bim/module/search/ui.py b/src/blenderbim/blenderbim/bim/module/search/ui.py index c45339201f..b02a328b7b 100644 --- a/src/blenderbim/blenderbim/bim/module/search/ui.py +++ b/src/blenderbim/blenderbim/bim/module/search/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel from blenderbim.bim.ifc import IfcStore diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index a161269d79..956326cb60 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/sequence/helper.py b/src/blenderbim/blenderbim/bim/module/sequence/helper.py index 3c6aec4199..6c5282b693 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/helper.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/helper.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import math import isodate diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 40ab311107..8f6ca758ae 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import re import os import bpy @@ -95,8 +114,7 @@ class EnableEditingWorkPlan(bpy.types.Operator): def execute(self, context): props = context.scene.BIMWorkPlanProperties - while len(props.work_plan_attributes) > 0: - props.work_plan_attributes.remove(0) + props.work_plan_attributes.clear() data = Data.work_plans[self.work_plan] @@ -260,8 +278,7 @@ class EnableEditingWorkSchedule(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMWorkScheduleProperties self.props.active_work_schedule_id = self.work_schedule - while len(self.props.work_schedule_attributes) > 0: - self.props.work_schedule_attributes.remove(0) + self.props.work_schedule_attributes.clear() self.enable_editing_work_schedule() self.props.editing_type = "WORK_SCHEDULE" return {"FINISHED"} @@ -289,8 +306,7 @@ class EnableEditingTasks(bpy.types.Operator): self.props = context.scene.BIMWorkScheduleProperties self.tprops = context.scene.BIMTaskTreeProperties self.props.active_work_schedule_id = self.work_schedule - while len(self.tprops.tasks) > 0: - self.tprops.tasks.remove(0) + self.tprops.tasks.clear() self.contracted_tasks = json.loads(self.props.contracted_tasks) self.sort_keys = { @@ -523,8 +539,7 @@ class EnableEditingTaskTime(bpy.types.Operator): task_time_id = Data.tasks[self.task]["TaskTime"] or self.add_task_time().id() - while len(props.task_time_attributes) > 0: - props.task_time_attributes.remove(0) + props.task_time_attributes.clear() data = Data.task_times[task_time_id] @@ -597,9 +612,7 @@ class EnableEditingTask(bpy.types.Operator): def execute(self, context): props = context.scene.BIMWorkScheduleProperties - while len(props.task_attributes) > 0: - props.task_attributes.remove(0) - + props.task_attributes.clear() data = Data.tasks[self.task] blenderbim.bim.helper.import_attributes("IfcTask", props.task_attributes, data) @@ -1024,8 +1037,7 @@ class EnableEditingWorkCalendar(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMWorkCalendarProperties - while len(self.props.work_calendar_attributes) > 0: - self.props.work_calendar_attributes.remove(0) + self.props.work_calendar_attributes.clear() data = Data.work_calendars[self.work_calendar] @@ -1131,8 +1143,7 @@ class EnableEditingWorkTime(bpy.types.Operator): def execute(self, context): self.props = context.scene.BIMWorkCalendarProperties - while len(self.props.work_time_attributes) > 0: - self.props.work_time_attributes.remove(0) + self.props.work_time_attributes.clear() data = Data.work_times[self.work_time] @@ -1469,8 +1480,7 @@ class EnableEditingSequenceAttributes(bpy.types.Operator): self.props = context.scene.BIMWorkScheduleProperties self.props.active_sequence_id = self.sequence self.props.editing_sequence_type = "ATTRIBUTES" - while len(self.props.sequence_attributes) > 0: - self.props.sequence_attributes.remove(0) + self.props.sequence_attributes.clear() self.enable_editing_sequence_attributes() return {"FINISHED"} @@ -1490,8 +1500,7 @@ class EnableEditingSequenceTimeLag(bpy.types.Operator): self.props = context.scene.BIMWorkScheduleProperties self.props.active_sequence_id = self.sequence self.props.editing_sequence_type = "TIME_LAG" - while len(self.props.time_lag_attributes) > 0: - self.props.time_lag_attributes.remove(0) + self.props.time_lag_attributes.clear() self.enable_editing_attributes() return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index 556878e411..61711c1ba7 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api import ifcopenshell.util.attribute diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 79083e4060..57a10f9ae4 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -1,7 +1,26 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import isodate import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes from ifcopenshell.api.sequence.data import Data from ifcopenshell.api.resource.data import Data as ResourceData import blenderbim.bim.module.sequence.helper as helper @@ -55,14 +74,7 @@ class BIM_PT_work_plans(Panel): self.draw_work_schedule_ui() def draw_editable_ui(self): - for attribute in self.props.work_plan_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.work_plan_attributes, self.layout) def draw_work_schedule_ui(self): row = self.layout.row(align=True) @@ -139,6 +151,37 @@ class BIM_PT_work_schedules(Panel): elif self.props.editing_type == "TASKS": self.draw_editable_task_ui(work_schedule_id) + def draw_task_operators(self): + row = self.layout.row(align=True) + row.alignment = "RIGHT" + ifc_definition_id = None + if self.tprops.tasks and self.props.active_task_index < len(self.tprops.tasks): + task = self.tprops.tasks[self.props.active_task_index] + ifc_definition_id = task.ifc_definition_id + if ifc_definition_id: + if self.props.active_task_id == ifc_definition_id: + if self.props.editing_task_type == "TASKTIME": + row.operator("bim.edit_task_time", text="", icon="CHECKMARK") + elif self.props.editing_task_type == "ATTRIBUTES": + row.operator("bim.edit_task", text="", icon="CHECKMARK") + row.operator("bim.disable_editing_task", text="", icon="CANCEL") + elif self.props.active_task_id: + row.operator("bim.add_task", text="", icon="ADD").task = ifc_definition_id + row.operator("bim.remove_task", text="", icon="X").task = ifc_definition_id + else: + row.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING").task = ifc_definition_id + row.operator( + "bim.select_task_related_products", icon="RESTRICT_SELECT_OFF", text="" + ).task = ifc_definition_id + row.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id + row.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = ifc_definition_id + row.operator( + "bim.enable_assigning_process_to_resources", text="", icon="COMMUNITY" + ).task = ifc_definition_id + row.operator("bim.enable_editing_task", text="", icon="GREASEPENCIL").task = ifc_definition_id + row.operator("bim.add_task", text="", icon="ADD").task = ifc_definition_id + row.operator("bim.remove_task", text="", icon="X").task = ifc_definition_id + def draw_column_ui(self): row = self.layout.row(align=True) row.prop(self.props, "column_types", text="") @@ -189,16 +232,10 @@ class BIM_PT_work_schedules(Panel): row.prop(self.props, "speed_multiplier", text="") def draw_editable_work_schedule_ui(self): - for attribute in self.props.work_schedule_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.work_schedule_attributes, self.layout) def draw_editable_task_ui(self, work_schedule_id): + self.draw_task_operators() self.layout.template_list( "BIM_UL_tasks", "", @@ -245,12 +282,12 @@ class BIM_PT_work_schedules(Panel): if self.props.active_sequence_id == sequence["id"]: if self.props.editing_sequence_type == "ATTRIBUTES": row.operator("bim.edit_sequence_attributes", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_sequence", text="", icon="X") + row.operator("bim.disable_editing_sequence", text="", icon="CANCEL") self.draw_editable_sequence_attributes_ui() elif self.props.editing_sequence_type == "TIME_LAG": op = row.operator("bim.edit_sequence_time_lag", text="", icon="CHECKMARK") op.lag_time = sequence["TimeLag"] - row.operator("bim.disable_editing_sequence", text="", icon="X") + row.operator("bim.disable_editing_sequence", text="", icon="CANCEL") self.draw_editable_sequence_time_lag_ui() else: if sequence["TimeLag"]: @@ -307,6 +344,7 @@ class BIM_PT_work_schedules(Panel): op.task = self.props.active_task_id op.resource = related_obect_id + class BIM_UL_task_columns(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): props = context.scene.BIMWorkScheduleProperties @@ -321,59 +359,21 @@ class BIM_UL_task_columns(UIList): class BIM_UL_tasks(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: - props = context.scene.BIMWorkScheduleProperties + self.props = context.scene.BIMWorkScheduleProperties task = IfcStore.get_file().by_id(item.ifc_definition_id) row = layout.row(align=True) - for i in range(0, item.level_index): - row.label(text="", icon="BLANK1") - if item.has_children: - if item.is_expanded: - row.operator( - "bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" - ).task = item.ifc_definition_id - else: - row.operator( - "bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" - ).task = item.ifc_definition_id - else: - row.label(text="", icon="DOT") - row.prop(item, "identification", emboss=False, text="") - row.prop(item, "name", emboss=False, text="") - for column in props.columns: - if column.name == "IfcTaskTime.ScheduleStart": - if item.derived_start: - row.label(text=item.derived_start + "*") - else: - row.prop(item, "start", emboss=False, text="") - elif column.name == "IfcTaskTime.ScheduleFinish": - if item.derived_finish: - row.label(text=item.derived_finish + "*") - else: - row.prop(item, "finish", emboss=False, text="") - elif column.name == "IfcTaskTime.ScheduleDuration": - if item.derived_duration: - row.label(text=item.derived_duration + "*") - else: - row.prop(item, "duration", emboss=False, text="") - elif column.name == "Controls.Calendar": - if item.derived_calendar: - row.label(text=item.derived_calendar + "*") - else: - row.label(text=item.calendar or "-") - else: - ifc_class, name = column.name.split(".") - if ifc_class == "IfcTask": - value = getattr(task, name) - elif ifc_class == "IfcTaskTime": - value = getattr(task.TaskTime, name) if task.TaskTime else None - if value is None: - value = "-" - row.label(text=str(value)) + self.draw_hierarchy(row, item) + + split1 = row.split(factor=0.1) + split1.prop(item, "identification", emboss=False, text="") + split2 = split1.split(factor=0.9 - min(0.5, 0.15 * len(self.props.columns))) + split2.prop(item, "name", emboss=False, text="") + + self.draw_custom_columns(split2, item, task) if context.active_object: oprops = context.active_object.BIMObjectProperties - row = layout.row(align=True) if oprops.ifc_definition_id in Data.tasks[item.ifc_definition_id]["OperatesOn"]: op = row.operator("bim.unassign_process", text="", icon="MARKER_HLT", emboss=False) @@ -389,7 +389,7 @@ class BIM_UL_tasks(UIList): op = row.operator("bim.assign_product", text="", icon="KEYFRAME", emboss=False) op.task = item.ifc_definition_id - if props.active_task_id and props.editing_task_type == "ATTRIBUTES": + if self.props.active_task_id and self.props.editing_task_type == "ATTRIBUTES": row.prop( item, "is_selected", @@ -398,47 +398,66 @@ class BIM_UL_tasks(UIList): emboss=False, ) - if props.active_task_id == item.ifc_definition_id: - if props.editing_task_type == "TASKTIME": - row.operator("bim.edit_task_time", text="", icon="CHECKMARK") - elif props.editing_task_type == "ATTRIBUTES": - row.operator("bim.edit_task", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_task", text="", icon="CANCEL") - elif props.active_task_id: - if props.editing_task_type == "SEQUENCE": + if self.props.active_task_id: + if self.props.editing_task_type == "SEQUENCE" and self.props.active_task_id != item.ifc_definition_id: if item.is_predecessor: - row.operator( - "bim.unassign_predecessor", text="", icon="BACK", emboss=False - ).task = item.ifc_definition_id + op = row.operator("bim.unassign_predecessor", text="", icon="BACK", emboss=False) else: - row.operator( - "bim.assign_predecessor", text="", icon="TRACKING_BACKWARDS", emboss=False - ).task = item.ifc_definition_id + op = row.operator("bim.assign_predecessor", text="", icon="TRACKING_BACKWARDS", emboss=False) + op.task = item.ifc_definition_id if item.is_successor: - row.operator( - "bim.unassign_successor", text="", icon="FORWARD", emboss=False - ).task = item.ifc_definition_id + op = row.operator("bim.unassign_successor", text="", icon="FORWARD", emboss=False) else: - row.operator( - "bim.assign_successor", text="", icon="TRACKING_FORWARDS", emboss=False - ).task = item.ifc_definition_id + op = row.operator("bim.assign_successor", text="", icon="TRACKING_FORWARDS", emboss=False) + op.task = item.ifc_definition_id - row.operator("bim.add_task", text="", icon="ADD").task = item.ifc_definition_id - row.operator("bim.remove_task", text="", icon="X").task = item.ifc_definition_id + def draw_hierarchy(self, row, item): + for i in range(0, item.level_index): + row.label(text="", icon="BLANK1") + if item.has_children: + if item.is_expanded: + row.operator( + "bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" + ).task = item.ifc_definition_id else: - row.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING").task = item.ifc_definition_id row.operator( - "bim.select_task_related_products", icon="RESTRICT_SELECT_OFF", text="" + "bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" ).task = item.ifc_definition_id - row.operator("bim.enable_editing_task_time", text="", icon="TIME").task = item.ifc_definition_id - row.operator( - "bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO" - ).task = item.ifc_definition_id - row.operator("bim.enable_assigning_process_to_resources", text="", icon="COMMUNITY").task = item.ifc_definition_id - row.operator("bim.enable_editing_task", text="", icon="GREASEPENCIL").task = item.ifc_definition_id - row.operator("bim.add_task", text="", icon="ADD").task = item.ifc_definition_id - row.operator("bim.remove_task", text="", icon="X").task = item.ifc_definition_id + else: + row.label(text="", icon="DOT") + + def draw_custom_columns(self, row, item, task): + for column in self.props.columns: + if column.name == "IfcTaskTime.ScheduleStart": + if item.derived_start: + row.label(text=item.derived_start + "*") + else: + row.prop(item, "start", emboss=False, text="") + elif column.name == "IfcTaskTime.ScheduleFinish": + if item.derived_finish: + row.label(text=item.derived_finish + "*") + else: + row.prop(item, "finish", emboss=False, text="") + elif column.name == "IfcTaskTime.ScheduleDuration": + if item.derived_duration: + row.label(text=item.derived_duration + "*") + else: + row.prop(item, "duration", emboss=False, text="") + elif column.name == "Controls.Calendar": + if item.derived_calendar: + row.label(text=item.derived_calendar + "*") + else: + row.label(text=item.calendar or "-") + else: + ifc_class, name = column.name.split(".") + if ifc_class == "IfcTask": + value = getattr(task, name) + elif ifc_class == "IfcTaskTime": + value = getattr(task.TaskTime, name) if task.TaskTime else None + if value is None: + value = "-" + row.label(text=str(value)) class BIM_PT_work_calendars(Panel): @@ -523,15 +542,7 @@ class BIM_PT_work_calendars(Panel): self.draw_editable_work_time_ui(work_time) def draw_editable_work_time_ui(self, work_time): - for attribute in self.props.work_time_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") - + draw_attributes(self.props.work_time_attributes, self.layout) if work_time["RecurrencePattern"]: self.draw_editable_recurrence_pattern_ui(Data.recurrence_patterns[work_time["RecurrencePattern"]]) else: @@ -599,11 +610,4 @@ class BIM_PT_work_calendars(Panel): row.prop(self.props, "occurrences") def draw_editable_ui(self): - for attribute in self.props.work_calendar_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.work_calendar_attributes, self.layout) diff --git a/src/blenderbim/blenderbim/bim/module/spatial/__init__.py b/src/blenderbim/blenderbim/bim/module/spatial/__init__.py index 8671309965..9335ac64d4 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/spatial/operator.py b/src/blenderbim/blenderbim/bim/module/spatial/operator.py index 9f7d5648d0..7f8fe7b3aa 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/operator.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api import ifcopenshell.util.element @@ -115,7 +134,7 @@ class RemoveContainer(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + obj = bpy.data.objects.get(self.obj, context.active_object) oprops = obj.BIMObjectProperties self.file = IfcStore.get_file() ifcopenshell.api.run( @@ -133,6 +152,7 @@ class RemoveContainer(bpy.types.Operator): for collection in obj.users_collection: collection.objects.unlink(obj) context.scene.collection.objects.link(obj) + context.view_layer.objects.active = obj return {"FINISHED"} def remove_collection(self, parent, child): @@ -143,6 +163,11 @@ class RemoveContainer(bpy.types.Operator): class CopyToContainer(bpy.types.Operator): + """ + Copies selected objects to selected containers + Check the mark next to a container in the container list to select it + Several containers can be selected at a time + """ bl_idname = "bim.copy_to_container" bl_label = "Copy To Container" bl_options = {"REGISTER", "UNDO"} @@ -153,7 +178,7 @@ class CopyToContainer(bpy.types.Operator): def _execute(self, context): self.file = IfcStore.get_file() - objects = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + objects = list(bpy.data.objects.get(self.obj, context.selected_objects)) sprops = context.scene.BIMSpatialProperties container_ids = [c.ifc_definition_id for c in sprops.spatial_elements if c.is_selected] for obj in objects: diff --git a/src/blenderbim/blenderbim/bim/module/spatial/prop.py b/src/blenderbim/blenderbim/bim/module/spatial/prop.py index dfea8823de..b9a4538f2a 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/prop.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from ifcopenshell.api.spatial.data import Data @@ -19,8 +38,7 @@ def getSpatialContainers(self, context, parent_id=None): Data.load(IfcStore.get_file()) self.file = IfcStore.get_file() props = context.scene.BIMSpatialProperties - while len(props.spatial_elements) > 0: - props.spatial_elements.remove(0) + props.spatial_elements.clear() if parent_id: props.active_decomposes_id = parent_id diff --git a/src/blenderbim/blenderbim/bim/module/spatial/ui.py b/src/blenderbim/blenderbim/bim/module/spatial/ui.py index f5ed85f61b..8d88132e5f 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/ui.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.spatial.data import Data diff --git a/src/blenderbim/blenderbim/bim/module/structural/__init__.py b/src/blenderbim/blenderbim/bim/module/structural/__init__.py index 7c49636828..edccdc92a5 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/structural/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/structural/operator.py b/src/blenderbim/blenderbim/bim/module/structural/operator.py index 6b036bccb0..5bb3e1469b 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/operator.py +++ b/src/blenderbim/blenderbim/bim/module/structural/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import json import ifcopenshell @@ -134,8 +153,7 @@ class EnableEditingStructuralBoundaryCondition(bpy.types.Operator): def execute(self, context): obj = context.active_object props = obj.BIMStructuralProperties - while len(props.boundary_condition_attributes) > 0: - props.boundary_condition_attributes.remove(0) + props.boundary_condition_attributes.clear() data = Data.boundary_conditions[self.boundary_condition] @@ -146,7 +164,7 @@ class EnableEditingStructuralBoundaryCondition(bpy.types.Operator): new.name = attribute.name() new.is_null = value is None new.is_optional = attribute.optional() - if data_type == "select": + if isinstance(data_type, tuple) and data_type[0] == "select": enum_items = [s.name() for s in ifcopenshell.util.attribute.get_select_items(attribute)] new.enum_items = json.dumps(enum_items) if isinstance(value, bool): @@ -221,8 +239,7 @@ class LoadStructuralAnalysisModels(bpy.types.Operator): def execute(self, context): props = context.scene.BIMStructuralProperties - while len(props.structural_analysis_models) > 0: - props.structural_analysis_models.remove(0) + props.structural_analysis_models.clear() for ifc_definition_id, structural_analysis_model in Data.structural_analysis_models.items(): new = props.structural_analysis_models.add() new.ifc_definition_id = ifc_definition_id @@ -279,15 +296,7 @@ class EditStructuralAnalysisModel(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMStructuralProperties - attributes = {} - for attribute in props.structural_analysis_model_attributes: - if attribute.is_null: - attributes[attribute.name] = None - else: - if attribute.data_type == "string": - attributes[attribute.name] = attribute.string_value - elif attribute.data_type == "enum": - attributes[attribute.name] = attribute.enum_value + attributes = blenderbim.bim.helper.export_attributes(props.structural_analysis_model_attributes) self.file = IfcStore.get_file() ifcopenshell.api.run( "structural.edit_structural_analysis_model", @@ -332,8 +341,7 @@ class EnableEditingStructuralAnalysisModel(bpy.types.Operator): def execute(self, context): props = context.scene.BIMStructuralProperties - while len(props.structural_analysis_model_attributes) > 0: - props.structural_analysis_model_attributes.remove(0) + props.structural_analysis_model_attributes.clear() data = Data.structural_analysis_models[self.structural_analysis_model] @@ -686,8 +694,7 @@ class EnableEditingStructuralLoadCase(bpy.types.Operator): self.props = context.scene.BIMStructuralProperties self.props.active_load_case_id = self.load_case self.props.load_case_editing_type = "ATTRIBUTES" - while len(self.props.load_case_attributes) > 0: - self.props.load_case_attributes.remove(0) + self.props.load_case_attributes.clear() data = Data.load_cases[self.load_case] blenderbim.bim.helper.import_attributes( "IfcStructuralLoadCase", self.props.load_case_attributes, data, self.import_attributes @@ -773,8 +780,7 @@ class EnableEditingStructuralLoadGroupActivities(bpy.types.Operator): return {"FINISHED"} def load_structural_activities(self): - while len(self.props.load_group_activities) > 0: - self.props.load_group_activities.remove(0) + self.props.load_group_activities.clear() for activity_id in Data.load_groups[self.load_group]["IsGroupedBy"]: activity = Data.structural_activities[activity_id] new = self.props.load_group_activities.add() @@ -845,8 +851,7 @@ class LoadStructuralLoads(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMStructuralProperties - while len(props.structural_loads) > 0: - props.structural_loads.remove(0) + props.structural_loads.clear() if props.filtered_structural_loads: names = [structural_load["Name"] or "Unnamed" for _, structural_load in Data.structural_loads.items()] for ifc_definition_id, structural_load in Data.structural_loads.items(): @@ -908,8 +913,7 @@ class EnableEditingStructuralLoad(bpy.types.Operator): def execute(self, context): props = context.scene.BIMStructuralProperties - while len(props.structural_load_attributes) > 0: - props.structural_load_attributes.remove(0) + props.structural_load_attributes.clear() data = Data.structural_loads[self.structural_load] blenderbim.bim.helper.import_attributes(data["type"], props.structural_load_attributes, data) @@ -991,8 +995,7 @@ class LoadBoundaryConditions(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() props = context.scene.BIMStructuralProperties - while len(props.boundary_conditions) > 0: - props.boundary_conditions.remove(0) + props.boundary_conditions.clear() if props.filtered_boundary_conditions: names = [ boundary_condition["Name"] or "Unnamed" for _, boundary_condition in Data.boundary_conditions.items() @@ -1071,8 +1074,7 @@ class EnableEditingBoundaryCondition(bpy.types.Operator): def execute(self, context): props = context.scene.BIMStructuralProperties - while len(props.boundary_condition_attributes) > 0: - props.boundary_condition_attributes.remove(0) + props.boundary_condition_attributes.clear() data = Data.boundary_conditions[self.boundary_condition] # blenderbim.bim.helper.import_attributes(data["type"], props.boundary_condition_attributes, data) diff --git a/src/blenderbim/blenderbim/bim/module/structural/prop.py b/src/blenderbim/blenderbim/bim/module/structural/prop.py index 513c7fcf03..5da6624f1c 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/prop.py +++ b/src/blenderbim/blenderbim/bim/module/structural/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.ifc import IfcStore from math import radians diff --git a/src/blenderbim/blenderbim/bim/module/structural/ui.py b/src/blenderbim/blenderbim/bim/module/structural/ui.py index 5ce31355b8..0f04cc71f2 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/ui.py +++ b/src/blenderbim/blenderbim/bim/module/structural/ui.py @@ -1,7 +1,27 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.helper import draw_attributes from ifcopenshell.api.structural.data import Data @@ -20,7 +40,7 @@ def draw_boundary_condition_ui(layout, boundary_condition_id, connection_id, pro if props.active_boundary_condition and props.active_boundary_condition == boundary_condition_id: row.label(text=data["type"], icon="CON_TRACKTO") row.operator("bim.edit_structural_boundary_condition", text="", icon="CHECKMARK").connection = connection_id - row.operator("bim.disable_editing_structural_boundary_condition", text="", icon="X") + row.operator("bim.disable_editing_structural_boundary_condition", text="", icon="CANCEL") elif props.active_boundary_condition and props.active_boundary_condition != boundary_condition_id: row.label(text=data["type"], icon="CON_TRACKTO") row.operator("bim.remove_structural_boundary_condition", text="", icon="X").connection = connection_id @@ -293,14 +313,7 @@ class BIM_PT_structural_analysis_models(Panel): self.draw_editable_ui(context) def draw_editable_ui(self, context): - for attribute in self.props.structural_analysis_model_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.structural_analysis_model_attributes, self.layout) class BIM_UL_structural_analysis_models(UIList): @@ -325,7 +338,7 @@ class BIM_UL_structural_analysis_models(UIList): if context.scene.BIMStructuralProperties.active_structural_analysis_model_id == item.ifc_definition_id: row.operator("bim.edit_structural_analysis_model", text="", icon="CHECKMARK") - row.operator("bim.disable_editing_structural_analysis_model", text="", icon="X") + row.operator("bim.disable_editing_structural_analysis_model", text="", icon="CANCEL") elif context.scene.BIMStructuralProperties.active_structural_analysis_model_id: op = row.operator("bim.remove_structural_analysis_model", text="", icon="X") op.structural_analysis_model = item.ifc_definition_id @@ -389,16 +402,7 @@ class BIM_PT_structural_load_cases(Panel): self.draw_editable_load_case_group_ui(load_case) def draw_editable_load_case_ui(self): - for attribute in self.props.load_case_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + draw_attributes(self.props.load_case_attributes, self.layout) def draw_editable_load_case_group_ui(self, load_case): box = self.layout.box() diff --git a/src/blenderbim/blenderbim/bim/module/style/__init__.py b/src/blenderbim/blenderbim/bim/module/style/__init__.py index e161508777..b60aac300f 100644 --- a/src/blenderbim/blenderbim/bim/module/style/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/style/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/style/operator.py b/src/blenderbim/blenderbim/bim/module/style/operator.py index 400a396d24..598cc9bc3f 100644 --- a/src/blenderbim/blenderbim/bim/module/style/operator.py +++ b/src/blenderbim/blenderbim/bim/module/style/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api import ifcopenshell.util.representation @@ -110,8 +129,7 @@ class EnableEditingStyle(bpy.types.Operator): def execute(self, context): material = bpy.data.materials.get(self.material) if self.material else context.active_object.active_material props = material.BIMStyleProperties - while len(props.attributes) > 0: - props.attributes.remove(0) + props.attributes.clear() data = Data.styles[material.BIMMaterialProperties.ifc_style_id] blenderbim.bim.helper.import_attributes("IfcSurfaceStyle", props.attributes, data) diff --git a/src/blenderbim/blenderbim/bim/module/style/prop.py b/src/blenderbim/blenderbim/bim/module/style/prop.py index 11fec121cd..fe0fcbf6b9 100644 --- a/src/blenderbim/blenderbim/bim/module/style/prop.py +++ b/src/blenderbim/blenderbim/bim/module/style/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.ifc import IfcStore from blenderbim.bim.prop import StrProperty, Attribute diff --git a/src/blenderbim/blenderbim/bim/module/style/ui.py b/src/blenderbim/blenderbim/bim/module/style/ui.py index 089db774cf..a2df554fb5 100644 --- a/src/blenderbim/blenderbim/bim/module/style/ui.py +++ b/src/blenderbim/blenderbim/bim/module/style/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import blenderbim.bim.helper from bpy.types import Panel from blenderbim.bim.ifc import IfcStore @@ -40,6 +59,8 @@ class BIM_PT_style_attributes(Panel): @classmethod def poll(cls, context): + if not IfcStore.get_file(): + return False try: return bool(context.active_object.active_material.BIMMaterialProperties.ifc_style_id) except: diff --git a/src/blenderbim/blenderbim/bim/module/system/__init__.py b/src/blenderbim/blenderbim/bim/module/system/__init__.py index 0059a29f4d..c5652828e0 100644 --- a/src/blenderbim/blenderbim/bim/module/system/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/system/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/system/operator.py b/src/blenderbim/blenderbim/bim/module/system/operator.py index ffff58bc78..51597aa7c0 100644 --- a/src/blenderbim/blenderbim/bim/module/system/operator.py +++ b/src/blenderbim/blenderbim/bim/module/system/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.util.attribute import ifcopenshell.api @@ -12,8 +31,7 @@ class LoadSystems(bpy.types.Operator): def execute(self, context): props = context.scene.BIMSystemProperties - while len(props.systems) > 0: - props.systems.remove(0) + props.systems.clear() for ifc_definition_id, system in Data.systems.items(): new = props.systems.add() new.ifc_definition_id = ifc_definition_id @@ -100,8 +118,7 @@ class EnableEditingSystem(bpy.types.Operator): def execute(self, context): props = context.scene.BIMSystemProperties - while len(props.system_attributes) > 0: - props.system_attributes.remove(0) + props.system_attributes.clear() data = Data.systems[self.system] diff --git a/src/blenderbim/blenderbim/bim/module/system/prop.py b/src/blenderbim/blenderbim/bim/module/system/prop.py index 5bed5a3fd9..f792ac8597 100644 --- a/src/blenderbim/blenderbim/bim/module/system/prop.py +++ b/src/blenderbim/blenderbim/bim/module/system/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from blenderbim.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup diff --git a/src/blenderbim/blenderbim/bim/module/system/ui.py b/src/blenderbim/blenderbim/bim/module/system/ui.py index 067dd038fc..516e382a90 100644 --- a/src/blenderbim/blenderbim/bim/module/system/ui.py +++ b/src/blenderbim/blenderbim/bim/module/system/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.system.data import Data diff --git a/src/blenderbim/blenderbim/bim/module/type/__init__.py b/src/blenderbim/blenderbim/bim/module/type/__init__.py index 09d2184577..329a930875 100644 --- a/src/blenderbim/blenderbim/bim/module/type/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/type/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index d332341a37..d1a889b459 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.util.schema import ifcopenshell.util.type @@ -117,13 +136,13 @@ class SelectType(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() - related_object = bpy.data.objects.get(self.related_object) if self.related_object else context.active_object + related_object = bpy.data.objects.get(self.related_object, context.active_object) oprops = related_object.BIMObjectProperties - obj = IfcStore.get_element( - ifcopenshell.util.element.get_type(self.file.by_id(oprops.ifc_definition_id)).GlobalId - ) - context.view_layer.objects.active = obj - obj.select_set(True) + element_type = ifcopenshell.util.element.get_type(self.file.by_id(oprops.ifc_definition_id)) + if element_type is not None: + obj = IfcStore.get_element(element_type.GlobalId) + context.view_layer.objects.active = obj + obj.select_set(True) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/type/prop.py b/src/blenderbim/blenderbim/bim/module/type/prop.py index 1b20b1367a..c5b6c2221d 100644 --- a/src/blenderbim/blenderbim/bim/module/type/prop.py +++ b/src/blenderbim/blenderbim/bim/module/type/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.util.type from blenderbim.bim.prop import StrProperty, Attribute @@ -88,5 +107,3 @@ class BIMTypeObjectProperties(PropertyGroup): is_editing_type: BoolProperty(name="Is Editing Type", update=updateTypeDropdowns) relating_type_class: EnumProperty(items=getApplicableTypes, name="Relating Type Class") relating_type: EnumProperty(items=getRelatingTypes, name="Relating Type") - # This is purely a UX thing - blank_relating_type: EnumProperty(items=[("None", "No Types Found", "")], name="Relating Type") diff --git a/src/blenderbim/blenderbim/bim/module/type/ui.py b/src/blenderbim/blenderbim/bim/module/type/ui.py index 0e319198da..84deb86a70 100644 --- a/src/blenderbim/blenderbim/bim/module/type/ui.py +++ b/src/blenderbim/blenderbim/bim/module/type/ui.py @@ -1,3 +1,23 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.bim.module.type.prop as type_prop from bpy.types import Panel from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.type.data import Data @@ -48,12 +68,12 @@ class BIM_PT_type(Panel): row = self.layout.row(align=True) row.prop(props, "relating_type_class", text="") - if props.relating_type: + if type_prop.getRelatingTypes(None, context): row.prop(props, "relating_type", text="") row.operator("bim.assign_type", icon="CHECKMARK", text="") else: - row.prop(props, "blank_relating_type", text="") - row.operator("bim.disable_editing_type", icon="X", text="") + row.label(text="No Types Found") + row.operator("bim.disable_editing_type", icon="CANCEL", text="") else: row = self.layout.row(align=True) name = "{}/{}".format( diff --git a/src/blenderbim/blenderbim/bim/module/unit/__init__.py b/src/blenderbim/blenderbim/bim/module/unit/__init__.py index a74eb70da1..a0942261df 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/unit/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator @@ -9,6 +28,7 @@ classes = ( operator.RemoveUnit, operator.AddMonetaryUnit, operator.AddSIUnit, + operator.AddContextDependentUnit, operator.EnableEditingUnit, operator.DisableEditingUnit, operator.EditUnit, diff --git a/src/blenderbim/blenderbim/bim/module/unit/operator.py b/src/blenderbim/blenderbim/bim/module/unit/operator.py index 9a4f3bfc00..d55c0cd3e6 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/operator.py +++ b/src/blenderbim/blenderbim/bim/module/unit/operator.py @@ -1,4 +1,24 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy +import json import ifcopenshell.api import ifcopenshell.util.unit import blenderbim.bim.helper @@ -78,8 +98,7 @@ class LoadUnits(bpy.types.Operator): def execute(self, context): props = context.scene.BIMUnitProperties - while len(props.units) > 0: - props.units.remove(0) + props.units.clear() for ifc_definition_id, unit in Data.units.items(): name = unit.get("Name", "") @@ -174,7 +193,7 @@ class AddSIUnit(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMUnitProperties self.file = IfcStore.get_file() - unit = ifcopenshell.api.run( + ifcopenshell.api.run( "unit.add_si_unit", self.file, unit_type=props.named_unit_types, @@ -185,6 +204,26 @@ class AddSIUnit(bpy.types.Operator): return {"FINISHED"} +class AddContextDependentUnit(bpy.types.Operator): + bl_idname = "bim.add_context_dependent_unit" + bl_label = "Add Context Dependent Unit" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + props = context.scene.BIMUnitProperties + self.file = IfcStore.get_file() + ifcopenshell.api.run( + "unit.add_context_dependent_unit", self.file, unit_type=props.named_unit_types, name="THINGAMAJIG" + ) + Data.load(self.file) + bpy.ops.bim.load_units() + return {"FINISHED"} + + + class EnableEditingUnit(bpy.types.Operator): bl_idname = "bim.enable_editing_unit" bl_label = "Enable Editing Unit" @@ -193,15 +232,26 @@ class EnableEditingUnit(bpy.types.Operator): def execute(self, context): props = context.scene.BIMUnitProperties - while len(props.unit_attributes) > 0: - props.unit_attributes.remove(0) - + props.unit_attributes.clear() data = Data.units[self.unit] - - blenderbim.bim.helper.import_attributes(data["type"], props.unit_attributes, data) + blenderbim.bim.helper.import_attributes( + data["type"], + props.unit_attributes, + data, + lambda name, prop, data: self.import_attributes(name, prop, data, context)) props.active_unit_id = self.unit return {"FINISHED"} + def import_attributes(self, name, prop, data, context): + if name == "Dimensions": + new = context.scene.BIMUnitProperties.unit_attributes.add() + new.name = name + new.is_null = data[name] is None + new.is_optional = False + new.data_type = "string" + new.string_value = json.dumps([e for e in IfcStore.get_file().by_id(data["id"]).Dimensions]) + return True + class DisableEditingUnit(bpy.types.Operator): bl_idname = "bim.disable_editing_unit" @@ -223,7 +273,7 @@ class EditUnit(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMUnitProperties - attributes = blenderbim.bim.helper.export_attributes(props.unit_attributes) + attributes = blenderbim.bim.helper.export_attributes(props.unit_attributes, self.export_attributes) self.file = IfcStore.get_file() unit = self.file.by_id(props.active_unit_id) if unit.is_a("IfcMonetaryUnit"): @@ -235,3 +285,11 @@ class EditUnit(bpy.types.Operator): Data.load(IfcStore.get_file()) bpy.ops.bim.load_units() return {"FINISHED"} + + def export_attributes(self, attributes, prop): + if prop.name == "Dimensions": + try: + attributes[prop.name] = json.loads(prop.get_value()) + except: + attributes[prop.name] = (0, 0, 0, 0, 0, 0, 0) + return True diff --git a/src/blenderbim/blenderbim/bim/module/unit/prop.py b/src/blenderbim/blenderbim/bim/module/unit/prop.py index 1d863fdb8d..d28d093c73 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/prop.py +++ b/src/blenderbim/blenderbim/bim/module/unit/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell import ifcopenshell.util.schema diff --git a/src/blenderbim/blenderbim/bim/module/unit/ui.py b/src/blenderbim/blenderbim/bim/module/unit/ui.py index 7b904a4b2d..7fb0f9d5c4 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/ui.py +++ b/src/blenderbim/blenderbim/bim/module/unit/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore @@ -24,7 +43,7 @@ class BIM_PT_units(Panel): self.props = context.scene.BIMUnitProperties row = self.layout.row(align=True) - row.label(text="{} Units Found".format(len(Data.unit_assignment)), icon="SNAP_GRID") + row.label(text="{} Units Found".format(len(Data.units)), icon="SNAP_GRID") if self.props.is_editing: row.operator("bim.disable_unit_editing_ui", text="", icon="CANCEL") else: @@ -43,8 +62,9 @@ class BIM_PT_units(Panel): elif self.props.unit_classes == "IfcSIUnit": row.prop(self.props, "named_unit_types", text="") row.operator("bim.add_si_unit", text="", icon="ADD") - else: + elif self.props.unit_classes == "IfcContextDependentUnit": row.prop(self.props, "named_unit_types", text="") + row.operator("bim.add_context_dependent_unit", text="", icon="ADD") self.layout.template_list( "BIM_UL_units", diff --git a/src/blenderbim/blenderbim/bim/module/void/__init__.py b/src/blenderbim/blenderbim/bim/module/void/__init__.py index f5b5a750d8..95c3503a82 100644 --- a/src/blenderbim/blenderbim/bim/module/void/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/void/__init__.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from . import ui, prop, operator diff --git a/src/blenderbim/blenderbim/bim/module/void/operator.py b/src/blenderbim/blenderbim/bim/module/void/operator.py index d859a87601..292aa1466b 100644 --- a/src/blenderbim/blenderbim/bim/module/void/operator.py +++ b/src/blenderbim/blenderbim/bim/module/void/operator.py @@ -1,5 +1,24 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy import ifcopenshell.api +import ifcopenshell.util.representation from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.void.data import Data from ifcopenshell.api.context.data import Data as ContextData @@ -16,21 +35,16 @@ class AddOpening(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object + obj = context.scene.objects.get(self.obj, context.active_object) opening = bpy.data.objects.get(self.opening) + if opening is None: + return {"FINISHED"} opening.display_type = "WIRE" if not opening.BIMObjectProperties.ifc_definition_id: - body_context_id = None - if not ContextData.is_loaded: - ContextData.load(IfcStore.get_file()) - for context in ContextData.contexts.values(): - for subcontext_id, subcontext in context["HasSubContexts"].items(): - if subcontext["ContextType"] == "Model" and subcontext["ContextIdentifier"] == "Body": - body_context_id = subcontext_id - break - if not body_context_id: + body_context = ifcopenshell.util.representation.get_context(IfcStore.get_file(), "Model", "Body") + if not body_context: return {"FINISHED"} - bpy.ops.bim.assign_class(obj=opening.name, ifc_class="IfcOpeningElement", context_id=body_context_id) + bpy.ops.bim.assign_class(obj=opening.name, ifc_class="IfcOpeningElement", context_id=body_context.id()) self.file = IfcStore.get_file() element_id = obj.BIMObjectProperties.ifc_definition_id @@ -55,6 +69,8 @@ class AddOpening(bpy.types.Operator): modifier = obj.modifiers.new("IfcOpeningElement", "BOOLEAN") modifier.operation = "DIFFERENCE" modifier.object = opening + modifier.solver = "EXACT" + modifier.use_self = True return {"FINISHED"} @@ -97,8 +113,10 @@ class AddFilling(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object - opening = bpy.data.objects.get(self.opening) if self.opening else context.scene.VoidProperties.desired_opening + obj = context.scene.objects.get(self.obj, context.active_object) + opening = context.scene.objects.get(self.opening, context.scene.VoidProperties.desired_opening) + if opening is None: + return {"FINISHED"} self.file = IfcStore.get_file() element_id = obj.BIMObjectProperties.ifc_definition_id ifcopenshell.api.run( @@ -178,15 +196,18 @@ class ToggleDecompositionParenting(bpy.types.Operator): def load_decompositions(self, parent_obj): element = self.file.by_id(parent_obj.BIMObjectProperties.ifc_definition_id) for rel in self.file.get_inverse(element): - if not (rel.is_a("IfcRelDecomposes") or rel.is_a("IfcRelFillsElement")): - continue - if rel[4] != element: - continue - if isinstance(rel[5], tuple): - for related_object in rel[5]: - self.add_decomposition(parent_obj, related_object) - else: - self.add_decomposition(parent_obj, rel[5]) + if rel.is_a("IfcRelDecomposes"): + if rel[4] != element: + continue + if isinstance(rel[5], tuple): + for related_object in rel[5]: + self.add_decomposition(parent_obj, related_object) + else: + self.add_decomposition(parent_obj, rel[5]) + elif rel.is_a("IfcRelFillsElement"): + if rel.RelatingOpeningElement != element: + continue + self.add_decomposition(parent_obj, rel.RelatedBuildingElement) def add_decomposition(self, parent_obj, child_element): child_obj = IfcStore.get_element(child_element.id()) diff --git a/src/blenderbim/blenderbim/bim/module/void/prop.py b/src/blenderbim/blenderbim/bim/module/void/prop.py index 4dd1185fe6..08866a8897 100644 --- a/src/blenderbim/blenderbim/bim/module/void/prop.py +++ b/src/blenderbim/blenderbim/bim/module/void/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import PropertyGroup from bpy.props import PointerProperty @@ -5,3 +24,4 @@ from bpy.props import PointerProperty class VoidProperties(PropertyGroup): desired_opening: PointerProperty(name="Desired Opening To Fill", type=bpy.types.Object) + diff --git a/src/blenderbim/blenderbim/bim/module/void/ui.py b/src/blenderbim/blenderbim/bim/module/void/ui.py index 48c29cdcdc..792867c864 100644 --- a/src/blenderbim/blenderbim/bim/module/void/ui.py +++ b/src/blenderbim/blenderbim/bim/module/void/ui.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import bpy from bpy.types import Panel from ifcopenshell.api.void.data import Data diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index 7278897ab8..14cf470a42 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import time @@ -45,8 +64,8 @@ class ExportIFC(bpy.types.Operator): def _execute(self, context): start = time.time() logger = logging.getLogger("ExportIFC") - path_log = os.path.join(bpy.context.scene.BIMProperties.data_dir, "process.log") - if not os.access(bpy.context.scene.BIMProperties.data_dir, os.W_OK): + path_log = os.path.join(context.scene.BIMProperties.data_dir, "process.log") + if not os.access(context.scene.BIMProperties.data_dir, os.W_OK): path_log = os.path.join(tempfile.mkdtemp(), "process.log") logging.basicConfig( filename=path_log, @@ -392,11 +411,13 @@ class RemoveSectionPlane(bpy.types.Operator): bl_label = "Remove Temporary Section Cutaway" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.active_object and bpy.data.node_groups.get("Section Override") + def execute(self, context): name = context.active_object.name section_override = bpy.data.node_groups.get("Section Override") - if not section_override: - return {"FINISHED"} for node in section_override.nodes: if node.type != "TEX_COORD" or node.object.name != name: continue @@ -478,8 +499,11 @@ class SetOverrideColour(bpy.types.Operator): bl_label = "Set Override Colour" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): - result = 0 for obj in context.selected_objects: obj.color = context.scene.BIMProperties.override_colour area = next(area for area in context.screen.areas if area.type == "VIEW_3D") @@ -492,6 +516,10 @@ class SetViewportShadowFromSun(bpy.types.Operator): bl_label = "Set Viewport Shadow from Sun" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.active_object + def execute(self, context): # The vector used for the light direction is a bit funny mat = Matrix(((-1.0, 0.0, 0.0, 0.0), (0.0, 0, 1.0, 0.0), (-0.0, -1.0, 0, 0.0), (0.0, 0.0, 0.0, 1.0))) @@ -534,17 +562,20 @@ class SnapSpacesTogether(bpy.types.Operator): bl_label = "Snap Spaces Together" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return context.selected_objects + def execute(self, context): threshold = 0.5 processed_polygons = set() - for obj in context.selected_objects: - if obj.type != "MESH": - continue + selected_mesh_objects = [o for o in context.selected_objects if o.type == "MESH"] + for obj in selected_mesh_objects: for polygon in obj.data.polygons: center = obj.matrix_world @ polygon.center distance = None - for obj2 in context.selected_objects: - if obj2 == obj or obj.type != "MESH": + for obj2 in selected_mesh_objects: + if obj2 == obj: continue result = obj2.ray_cast(obj2.matrix_world.inverted() @ center, polygon.normal, distance=threshold) if not result[0]: diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index 4e71c57112..21fb7b6d3a 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -1,3 +1,22 @@ + +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + import os import bpy import json @@ -126,42 +145,74 @@ class StrProperty(PropertyGroup): pass -def updateAttributeStringValue(self, context): - updateAttributeValue(self, self.string_value) - - -def updateAttributeBoolValue(self, context): - updateAttributeValue(self, self.bool_value) - - -def updateAttributeIntValue(self, context): - updateAttributeValue(self, self.int_value) - - -def updateAttributeFloatValue(self, context): - updateAttributeValue(self, self.float_value) - - -def updateAttributeEnumValue(self, context): - updateAttributeValue(self, self.enum_value) - - -def updateAttributeValue(self, value): - if value: - self.is_null = False +def updateAttributeValue(self, context): + value_name = self.get_value_name() + if value_name: + value_names = [value_name] + else: + # We may not have a value name in