From de4659570a913482359f631bb19e88854334d125 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Dec 2021 13:31:23 +1100 Subject: [PATCH] See #1917. Refactor and fix warning message when you haven't got any contexts in a project yet. --- .../blenderbim/bim/module/debug/ui.py | 4 +- .../bim/module/geometry/operator.py | 11 ++-- .../blenderbim/bim/module/project/operator.py | 4 +- .../blenderbim/bim/module/root/data.py | 55 +++++++++++++++++++ .../blenderbim/bim/module/root/operator.py | 5 +- .../blenderbim/bim/module/root/prop.py | 8 +++ .../blenderbim/bim/module/root/ui.py | 5 +- src/blenderbim/blenderbim/bim/prop.py | 22 -------- .../test/bim/feature/geometry.feature | 6 +- src/blenderbim/test/bim/feature/model.feature | 2 +- 10 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 src/blenderbim/blenderbim/bim/module/root/data.py diff --git a/src/blenderbim/blenderbim/bim/module/debug/ui.py b/src/blenderbim/blenderbim/bim/module/debug/ui.py index 7a0a52de05..1a70377a28 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/ui.py +++ b/src/blenderbim/blenderbim/bim/module/debug/ui.py @@ -59,7 +59,9 @@ class BIM_PT_debug(Panel): row.operator("bim.select_high_polygon_meshes").threshold = context.scene.BIMDebugProperties.number_of_polygons row.prop(props, "number_of_polygons", text="") row = layout.split(factor=0.7, align=True) - row.operator("bim.select_highest_polygon_meshes").percentile = context.scene.BIMDebugProperties.percentile_of_polygons + row.operator( + "bim.select_highest_polygon_meshes" + ).percentile = context.scene.BIMDebugProperties.percentile_of_polygons row.prop(props, "percentile_of_polygons", text="") layout.label(text="Inspector:") diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 71554ea171..594b084573 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -30,12 +30,13 @@ import blenderbim.core.style import blenderbim.core.root import blenderbim.tool as tool import blenderbim.bim.handler -from blenderbim.bim.ifc import IfcStore -from blenderbim.bim import import_ifc +from mathutils import Vector from ifcopenshell.api.geometry.data import Data from ifcopenshell.api.context.data import Data as ContextData from ifcopenshell.api.void.data import Data as VoidData -from mathutils import Vector +from blenderbim.bim import import_ifc +from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.root.prop import get_contexts class Operator: @@ -67,7 +68,9 @@ class AddRepresentation(bpy.types.Operator, Operator): profile_set_usage: bpy.props.IntProperty() def _execute(self, context): - ifc_context = self.context_id or int(context.scene.BIMProperties.contexts or "0") or None + ifc_context = self.context_id + if not ifc_context and get_contexts(self, context): + ifc_context = int(context.scene.BIMRootProperties.contexts or "0") or None if ifc_context: ifc_context = tool.Ifc.get().by_id(ifc_context) obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index ff36a71b85..3aa5423207 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -91,8 +91,8 @@ class CreateProject(bpy.types.Operator): tool.Ifc, context_type="Plan", context_identifier="Annotation", target_view="PLAN_VIEW", parent=plan ) - ContextData.load(tool.Ifc.get()) - context.scene.BIMProperties.contexts = str(body_context.id()) + blenderbim.bim.handler.refresh_ui_data() + context.scene.BIMRootProperties.contexts = str(body_context.id()) bpy.ops.bim.assign_class(obj=site.name, ifc_class="IfcSite") bpy.ops.bim.assign_class(obj=building.name, ifc_class="IfcBuilding") diff --git a/src/blenderbim/blenderbim/bim/module/root/data.py b/src/blenderbim/blenderbim/bim/module/root/data.py new file mode 100644 index 0000000000..fe4fa787c3 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/root/data.py @@ -0,0 +1,55 @@ +# 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 blenderbim.tool as tool + + +def refresh(): + IfcClassData.is_loaded = False + + +class IfcClassData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.is_loaded = True + cls.data = { + "contexts": cls.contexts(), + } + + @classmethod + def contexts(cls): + results = [] + for element in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False): + results.append((str(element.id()), element.ContextType or "Unnamed", "")) + for element in tool.Ifc.get().by_type("IfcGeometricRepresentationSubContext", include_subtypes=False): + results.append( + ( + str(element.id()), + "{}/{}/{}".format( + element.ContextType or "Unnamed", + element.ContextIdentifier or "Unnamed", + element.TargetView or "Unnamed", + ), + "", + ) + ) + return results diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index ef57430072..4e909443b2 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -31,6 +31,7 @@ import blenderbim.core.root as core import blenderbim.tool as tool from ifcopenshell.api.void.data import Data as VoidData from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.root.prop import get_contexts class Operator: @@ -156,7 +157,9 @@ class AssignClass(bpy.types.Operator): IfcStore.link_element(product, obj) if self.should_add_representation: - ifc_context = self.context_id or int(context.scene.BIMProperties.contexts or "0") or None + ifc_context = self.context_id + if not ifc_context and get_contexts(self, context): + ifc_context = int(context.scene.BIMRootProperties.contexts or "0") or None if ifc_context: ifc_context = tool.Ifc.get().by_id(ifc_context) blenderbim.core.geometry.add_representation( diff --git a/src/blenderbim/blenderbim/bim/module/root/prop.py b/src/blenderbim/blenderbim/bim/module/root/prop.py index 00d28fd207..fd96b0c7cc 100644 --- a/src/blenderbim/blenderbim/bim/module/root/prop.py +++ b/src/blenderbim/blenderbim/bim/module/root/prop.py @@ -19,6 +19,7 @@ import bpy import ifcopenshell import ifcopenshell.util.schema +from blenderbim.bim.module.root.data import IfcClassData from blenderbim.bim.ifc import IfcStore from bpy.types import PropertyGroup from bpy.props import ( @@ -109,7 +110,14 @@ def getIfcClasses(self, context): return classes_enum +def get_contexts(self, context): + if not IfcClassData.is_loaded: + IfcClassData.load() + return IfcClassData.data["contexts"] + + class BIMRootProperties(PropertyGroup): + contexts: EnumProperty(items=get_contexts, name="Contexts") ifc_product: EnumProperty(items=getIfcProducts, name="Products", update=refreshClasses) ifc_class: EnumProperty(items=getIfcClasses, name="Class", update=refreshPredefinedTypes) ifc_predefined_type: EnumProperty(items=getIfcPredefinedTypes, name="Predefined Type", default=None) diff --git a/src/blenderbim/blenderbim/bim/module/root/ui.py b/src/blenderbim/blenderbim/bim/module/root/ui.py index 10f28fd70f..294f9fcc7a 100644 --- a/src/blenderbim/blenderbim/bim/module/root/ui.py +++ b/src/blenderbim/blenderbim/bim/module/root/ui.py @@ -21,6 +21,7 @@ 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 +from blenderbim.bim.module.root.data import IfcClassData class BIM_PT_class(Panel): @@ -37,6 +38,8 @@ class BIM_PT_class(Panel): return IfcStore.get_file() def draw(self, context): + if not IfcClassData.is_loaded: + IfcClassData.load() props = context.active_object.BIMObjectProperties if props.ifc_definition_id: if props.ifc_definition_id not in Data.products: @@ -100,4 +103,4 @@ class BIM_PT_class(Panel): row = self.layout.row() row.prop(props, "ifc_userdefined_type") row = self.layout.row() - row.prop(context.scene.BIMProperties, "contexts") + row.prop(context.scene.BIMRootProperties, "contexts") diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index 1106f59212..4fbb62f62b 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -114,27 +114,6 @@ def getMaterialPsetNames(self, context): return materialpsetnames_enum -def getContexts(self, context): - from ifcopenshell.api.context.data import Data - - if not Data.is_loaded: - Data.load(IfcStore.get_file()) - results = [] - for ifc_id, context in Data.contexts.items(): - results.append((str(ifc_id), context["ContextType"], "")) - for ifc_id2, subcontext in context["HasSubContexts"].items(): - results.append( - ( - str(ifc_id2), - "{}/{}/{}".format( - subcontext["ContextType"], subcontext["ContextIdentifier"], subcontext["TargetView"] - ), - "", - ) - ) - return results - - class StrProperty(PropertyGroup): pass @@ -235,7 +214,6 @@ class BIMProperties(PropertyGroup): ifc_file: StringProperty(name="IFC File", update=update_ifc_file) export_schema: EnumProperty(items=[("IFC4", "IFC4", ""), ("IFC2X3", "IFC2X3", "")], name="IFC Schema") last_transaction: StringProperty(name="Last Transaction") - contexts: EnumProperty(items=getContexts, name="Contexts") should_section_selected_objects: BoolProperty(name="Section Selected Objects", default=False) section_plane_colour: FloatVectorProperty( name="Temporary Section Cutaway Colour", subtype="COLOR", default=(1, 0, 0), min=0.0, max=1.0 diff --git a/src/blenderbim/test/bim/feature/geometry.feature b/src/blenderbim/test/bim/feature/geometry.feature index 6fb4f7f6b1..ea2b7fbcc4 100644 --- a/src/blenderbim/test/bim/feature/geometry.feature +++ b/src/blenderbim/test/bim/feature/geometry.feature @@ -20,7 +20,7 @@ Scenario: Add representation And the object "IfcWall/Cube" is selected Then the object "IfcWall/Cube" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW" When the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()" - And I set "scene.BIMProperties.contexts" to "{context}" + And I set "scene.BIMRootProperties.contexts" to "{context}" And I press "bim.add_representation" Then the object "IfcWall/Cube" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW" @@ -37,7 +37,7 @@ Scenario: Add representation - add a new representation to a typed instance And the object "IfcWall/Instance.001" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW" When the object "IfcWall/Instance" is selected And the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()" - And I set "scene.BIMProperties.contexts" to "{context}" + And I set "scene.BIMRootProperties.contexts" to "{context}" And I press "bim.add_representation" Then the object "IfcWall/Instance" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW" And the object "IfcWall/Instance.001" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW" @@ -80,7 +80,7 @@ Scenario: Switch representation - current edited representation is updated prior And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" And I press "bim.assign_class" And the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()" - And I set "scene.BIMProperties.contexts" to "{context}" + And I set "scene.BIMRootProperties.contexts" to "{context}" And I press "bim.add_representation" When the object "IfcWall/Cube" is scaled to "2" And the variable "representation" is "{ifc}.by_type('IfcShapeRepresentation')[0].id()" diff --git a/src/blenderbim/test/bim/feature/model.feature b/src/blenderbim/test/bim/feature/model.feature index 52b63b988d..ede7e3628c 100644 --- a/src/blenderbim/test/bim/feature/model.feature +++ b/src/blenderbim/test/bim/feature/model.feature @@ -41,7 +41,7 @@ Scenario: Add type instance - add a mesh where existing instances have changed c And the object "IfcWall/Instance" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW" And the object "IfcWall/Instance" is selected And the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()" - And I set "scene.BIMProperties.contexts" to "{context}" + And I set "scene.BIMRootProperties.contexts" to "{context}" And I press "bim.add_representation" And the object "IfcWall/Instance" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW" When I press "bim.add_type_instance"