From 52739418d858f1509800fa9c3caaa0d502d94bb8 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 27 Jan 2022 17:21:11 +1100 Subject: [PATCH] Fix #1514. You can now customise the default names of occurrences create from a type. --- .../blenderbim/bim/module/model/product.py | 2 +- .../blenderbim/bim/module/model/profile.py | 10 ++-- .../blenderbim/bim/module/model/prop.py | 2 + .../blenderbim/bim/module/model/slab.py | 11 ++-- .../blenderbim/bim/module/model/wall.py | 2 +- .../blenderbim/bim/module/owner/operator.py | 1 - src/blenderbim/blenderbim/bim/ui.py | 6 +++ src/blenderbim/blenderbim/core/tool.py | 5 ++ src/blenderbim/blenderbim/tool/__init__.py | 1 + src/blenderbim/blenderbim/tool/model.py | 37 +++++++++++++ src/blenderbim/test/tool/test_model.py | 52 +++++++++++++++++++ 11 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 src/blenderbim/blenderbim/tool/model.py create mode 100644 src/blenderbim/test/tool/test_model.py diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 0f8f4bdeda..76a743105e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -108,7 +108,7 @@ class AddTypeInstance(bpy.types.Operator): ] mesh = bpy.data.meshes.new(name="Instance") mesh.from_pydata(verts, edges, faces) - obj = bpy.data.objects.new("Instance", mesh) + obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(relating_type, instance_class), mesh) obj.location = context.scene.cursor.location collection = context.view_layer.active_layer_collection.collection collection.objects.link(obj) diff --git a/src/blenderbim/blenderbim/bim/module/model/profile.py b/src/blenderbim/blenderbim/bim/module/model/profile.py index fb3ef464fd..1c3e6bbe26 100644 --- a/src/blenderbim/blenderbim/bim/module/model/profile.py +++ b/src/blenderbim/blenderbim/bim/module/model/profile.py @@ -138,18 +138,18 @@ class DumbProfileGenerator: [0, 2, 6, 4], ] + ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema) + # Standard cases are deprecated, so let's cull them + ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] + mesh = bpy.data.meshes.new(name="Dumb Profile") mesh.from_pydata(verts, edges, faces) - obj = bpy.data.objects.new("Profile", mesh) + obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) obj.location = self.location if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id: obj.location[2] = self.collection_obj.location[2] self.collection.objects.link(obj) - ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema) - # Standard cases are deprecated, so let's cull them - ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] - obj.name = ifc_class[3:] bpy.ops.bim.assign_class(obj=obj.name, ifc_class=ifc_class, should_add_representation=False) if self.relating_type.is_a() in ["IfcBeamType", "IfcMemberType"]: diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 5852118f9b..378794653f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -53,3 +53,5 @@ def update_ifc_class(self, context): class BIMModelProperties(PropertyGroup): ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="IFC Class", update=update_ifc_class) relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type") + occurrence_name_style: bpy.props.EnumProperty(items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")], name="Occurrence Name Style") + occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function") diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index 517a7cf0ec..622f447e83 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -278,19 +278,18 @@ class DumbSlabGenerator: edges = [] faces = [[0, 3, 2, 1]] + ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema) + # Standard cases are deprecated, so let's cull them + ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] + mesh = bpy.data.meshes.new(name="Dumb Slab") mesh.from_pydata(verts, edges, faces) - obj = bpy.data.objects.new("Slab", mesh) + obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) modifier = obj.modifiers.new("Slab Depth", "SOLIDIFY") modifier.use_even_offset = True modifier.offset = 1 modifier.thickness = self.depth - ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema) - # Standard cases are deprecated, so let's cull them - ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] - - obj.name = ifc_class[3:] obj.location = self.location if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id: obj.location[2] = self.collection_obj.location[2] - self.depth diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index 513d929a8f..72a2c33c45 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -795,7 +795,7 @@ class DumbWallGenerator: # Standard cases are deprecated, so let's cull them ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] - obj = bpy.data.objects.new(ifc_class[3:], mesh) + obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) obj.location = self.location obj.rotation_euler[2] = self.rotation if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id: diff --git a/src/blenderbim/blenderbim/bim/module/owner/operator.py b/src/blenderbim/blenderbim/bim/module/owner/operator.py index f4aea75214..45b9c7f503 100644 --- a/src/blenderbim/blenderbim/bim/module/owner/operator.py +++ b/src/blenderbim/blenderbim/bim/module/owner/operator.py @@ -17,7 +17,6 @@ # along with BlenderBIM Add-on. If not, see . import bpy -import ifcopenshell.api import blenderbim.tool as tool import blenderbim.core.owner as core import blenderbim.bim.handler diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 23c49c4775..796ec67806 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -146,6 +146,12 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): row.prop(self, "should_hide_empty_props") row = layout.row() row.prop(self, "should_play_chaching_sound") + + row = layout.row() + row.prop(context.scene.BIMModelProperties, "occurrence_name_style") + row = layout.row() + row.prop(context.scene.BIMModelProperties, "occurrence_name_function") + row = layout.row() row.operator("bim.configure_visibility") diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index f47f870401..ebadfb8186 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -233,6 +233,11 @@ class Misc: def split_objects_with_cutter(cls, objs, cutter): pass +@interface +class Model: + pass + + @interface class Patch: def run_migrate_patch(cls, infile, outfile, schema): pass diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index 137d4d6102..82b9d537a7 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -30,6 +30,7 @@ from blenderbim.tool.ifc import Ifc from blenderbim.tool.library import Library from blenderbim.tool.material import Material from blenderbim.tool.misc import Misc +from blenderbim.tool.model import Model from blenderbim.tool.owner import Owner from blenderbim.tool.patch import Patch from blenderbim.tool.pset import Pset diff --git a/src/blenderbim/blenderbim/tool/model.py b/src/blenderbim/blenderbim/tool/model.py new file mode 100644 index 0000000000..4e01dc38fb --- /dev/null +++ b/src/blenderbim/blenderbim/tool/model.py @@ -0,0 +1,37 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 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.core.tool +import blenderbim.tool as tool + + +class Model(blenderbim.core.tool.Model): + @classmethod + def generate_occurrence_name(cls, element_type, ifc_class): + props = bpy.context.scene.BIMModelProperties + if props.occurrence_name_style == "CLASS": + return ifc_class[3:] + elif props.occurrence_name_style == "TYPE": + return element_type.Name or "Unnamed" + elif props.occurrence_name_style == "CUSTOM": + try: + # Power users gonna power + return eval(props.occurrence_name_function) or "Instance" + except: + return "Instance" diff --git a/src/blenderbim/test/tool/test_model.py b/src/blenderbim/test/tool/test_model.py new file mode 100644 index 0000000000..005aa0e3d5 --- /dev/null +++ b/src/blenderbim/test/tool/test_model.py @@ -0,0 +1,52 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 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 blenderbim.core.tool +import blenderbim.tool as tool +from test.bim.bootstrap import NewFile +from blenderbim.tool.model import Model as subject + + +class TestImplementsTool(NewFile): + def test_run(self): + assert isinstance(subject(), blenderbim.core.tool.Model) + + +class TestGenerateOccurrenceName(NewFile): + def test_generating_based_on_class(self): + ifc = ifcopenshell.file() + element_type = ifc.createIfcWallType(Name="Foobar") + bpy.context.scene.BIMModelProperties.occurrence_name_style = "CLASS" + assert subject.generate_occurrence_name(element_type, "IfcWall") == "Wall" + + def test_generating_based_on_type_name(self): + ifc = ifcopenshell.file() + element_type = ifc.createIfcWallType() + bpy.context.scene.BIMModelProperties.occurrence_name_style = "TYPE" + assert subject.generate_occurrence_name(element_type, "IfcWall") == "Unnamed" + element_type.Name = "Foobar" + assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar" + + def test_generating_based_on_a_custom_function(self): + ifc = ifcopenshell.file() + element_type = ifc.createIfcWallType() + bpy.context.scene.BIMModelProperties.occurrence_name_style = "CUSTOM" + bpy.context.scene.BIMModelProperties.occurrence_name_function = "\"Foobar\"" + assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar"