mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 14:33:28 +00:00
Fix #2364. Bug where classifications couldn't be added in IFC2X3.
This commit is contained in:
@@ -39,6 +39,8 @@ class IfcStore:
|
|||||||
edited_objs = set()
|
edited_objs = set()
|
||||||
pset_template_path = ""
|
pset_template_path = ""
|
||||||
pset_template_file = None
|
pset_template_file = None
|
||||||
|
classification_path = ""
|
||||||
|
classification_file = None
|
||||||
library_path = ""
|
library_path = ""
|
||||||
library_file = None
|
library_file = None
|
||||||
element_listeners = set()
|
element_listeners = set()
|
||||||
|
|||||||
@@ -20,18 +20,19 @@ import bpy
|
|||||||
from . import ui, prop, operator
|
from . import ui, prop, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.LoadClassificationLibrary,
|
|
||||||
operator.AddClassification,
|
operator.AddClassification,
|
||||||
operator.RemoveClassification,
|
|
||||||
operator.EnableEditingClassification,
|
|
||||||
operator.DisableEditingClassification,
|
|
||||||
operator.EditClassification,
|
|
||||||
operator.RemoveClassificationReference,
|
|
||||||
operator.EnableEditingClassificationReference,
|
|
||||||
operator.DisableEditingClassificationReference,
|
|
||||||
operator.EditClassificationReference,
|
|
||||||
operator.AddClassificationReference,
|
operator.AddClassificationReference,
|
||||||
operator.ChangeClassificationLevel,
|
operator.ChangeClassificationLevel,
|
||||||
|
operator.DisableEditingClassification,
|
||||||
|
operator.DisableEditingClassificationReference,
|
||||||
|
operator.DisableEditingClassificationReferences,
|
||||||
|
operator.EditClassification,
|
||||||
|
operator.EditClassificationReference,
|
||||||
|
operator.EnableEditingClassification,
|
||||||
|
operator.EnableEditingClassificationReference,
|
||||||
|
operator.LoadClassificationLibrary,
|
||||||
|
operator.RemoveClassification,
|
||||||
|
operator.RemoveClassificationReference,
|
||||||
prop.ClassificationReference,
|
prop.ClassificationReference,
|
||||||
prop.BIMClassificationProperties,
|
prop.BIMClassificationProperties,
|
||||||
prop.BIMClassificationReferenceProperties,
|
prop.BIMClassificationReferenceProperties,
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.date
|
||||||
|
import ifcopenshell.util.classification
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
ClassificationsData.is_loaded = False
|
||||||
|
ClassificationReferencesData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class ClassificationsData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.is_loaded = True
|
||||||
|
cls.data["has_classification_file"] = cls.has_classification_file()
|
||||||
|
cls.data["classifications"] = cls.classifications()
|
||||||
|
cls.data["available_classifications"] = cls.available_classifications()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def has_classification_file(cls):
|
||||||
|
return bool(IfcStore.classification_file)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def classifications(cls):
|
||||||
|
results = []
|
||||||
|
for element in tool.Ifc.get().by_type("IfcClassification"):
|
||||||
|
data = element.get_info()
|
||||||
|
if IfcStore.classification_file.schema == "IFC2X3" and element.EditionDate:
|
||||||
|
data["EditionDate"] = ifcopenshell.util.date.ifc2datetime(data["EditionDate"])
|
||||||
|
results.append(data)
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def available_classifications(cls):
|
||||||
|
if not IfcStore.classification_file:
|
||||||
|
return []
|
||||||
|
return [(str(e.id()), e.Name, "") for e in IfcStore.classification_file.by_type("IfcClassification")]
|
||||||
|
|
||||||
|
|
||||||
|
class ClassificationReferencesData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.is_loaded = True
|
||||||
|
cls.data["references"] = cls.references()
|
||||||
|
cls.data["is_available_classification_added"] = cls.is_available_classification_added()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def references(cls):
|
||||||
|
results = []
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if element:
|
||||||
|
for reference in ifcopenshell.util.classification.get_references(element):
|
||||||
|
data = reference.get_info()
|
||||||
|
del data["ReferencedSource"]
|
||||||
|
results.append(data)
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_available_classification_added(cls):
|
||||||
|
if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"):
|
||||||
|
return False
|
||||||
|
props = bpy.context.scene.BIMClassificationProperties
|
||||||
|
name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name
|
||||||
|
return name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
# Copyright (C) 2020-2022 Dion Moult <dion@thinkmoult.com>
|
||||||
#
|
#
|
||||||
# This file is part of BlenderBIM Add-on.
|
# This file is part of BlenderBIM Add-on.
|
||||||
#
|
#
|
||||||
@@ -18,46 +18,40 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.bim.helper
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.classification.data import Data
|
|
||||||
from blenderbim.bim.module.classification.prop import getClassifications, getReferences
|
|
||||||
|
|
||||||
|
|
||||||
class LoadClassificationLibrary(bpy.types.Operator):
|
class LoadClassificationLibrary(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.load_classification_library"
|
bl_idname = "bim.load_classification_library"
|
||||||
bl_label = "Load Classification Library"
|
bl_label = "Load Classification Library"
|
||||||
filename_ext = ".ifc"
|
filename_ext = ".ifc"
|
||||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
||||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
Data.load_library(self.filepath)
|
|
||||||
getClassifications(self, context)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
context.window_manager.fileselect_add(self)
|
context.window_manager.fileselect_add(self)
|
||||||
return {"RUNNING_MODAL"}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
IfcStore.classification_file = ifcopenshell.open(self.filepath)
|
||||||
|
|
||||||
class AddClassification(bpy.types.Operator):
|
|
||||||
|
class AddClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_classification"
|
bl_idname = "bim.add_classification"
|
||||||
bl_label = "Add Classification"
|
bl_label = "Add Classification"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMClassificationProperties
|
props = context.scene.BIMClassificationProperties
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"classification.add_classification",
|
"classification.add_classification",
|
||||||
IfcStore.get_file(),
|
tool.Ifc.get(),
|
||||||
**{"classification": Data.library_file.by_id(int(props.available_classifications))},
|
classification=IfcStore.classification_file.by_id(int(props.available_classifications)),
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingClassification(bpy.types.Operator):
|
class EnableEditingClassification(bpy.types.Operator):
|
||||||
@@ -67,19 +61,21 @@ class EnableEditingClassification(bpy.types.Operator):
|
|||||||
classification: bpy.props.IntProperty()
|
classification: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
def callback(name, prop, data):
|
||||||
|
if name == "ReferenceTokens":
|
||||||
|
new = bpy.context.scene.BIMGeoreferenceProperties.projected_crs.add()
|
||||||
|
new.name = name
|
||||||
|
new.data_type = "string"
|
||||||
|
new.is_null = data[name] is None
|
||||||
|
new.is_optional = True
|
||||||
|
new.string_value = "" if new.is_null else json.dumps(data[name])
|
||||||
|
return True
|
||||||
|
|
||||||
props = context.scene.BIMClassificationProperties
|
props = context.scene.BIMClassificationProperties
|
||||||
props.classification_attributes.clear()
|
props.classification_attributes.clear()
|
||||||
classification_data = Data.classifications[self.classification]
|
blenderbim.bim.helper.import_attributes2(
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcClassification").all_attributes():
|
tool.Ifc.get().by_id(self.classification), props.classification_attributes, callback
|
||||||
new = props.classification_attributes.add()
|
)
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = classification_data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = "string"
|
|
||||||
if attribute.name() == "ReferenceTokens":
|
|
||||||
new.string_value = "" if new.is_null else json.dumps(classification_data[attribute.name()])
|
|
||||||
else:
|
|
||||||
new.string_value = "" if new.is_null else classification_data[attribute.name()]
|
|
||||||
props.active_classification_id = self.classification
|
props.active_classification_id = self.classification
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -94,34 +90,26 @@ class DisableEditingClassification(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RemoveClassification(bpy.types.Operator):
|
class RemoveClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.remove_classification"
|
bl_idname = "bim.remove_classification"
|
||||||
bl_label = "Remove Classification"
|
bl_label = "Remove Classification"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
classification: bpy.props.IntProperty()
|
classification: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"classification.remove_classification",
|
"classification.remove_classification",
|
||||||
self.file,
|
tool.Ifc.get(),
|
||||||
**{"classification": self.file.by_id(self.classification)},
|
classification=self.file.by_id(self.classification),
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EditClassification(bpy.types.Operator):
|
class EditClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.edit_classification"
|
bl_idname = "bim.edit_classification"
|
||||||
bl_label = "Edit Classification"
|
bl_label = "Edit Classification"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMClassificationProperties
|
props = context.scene.BIMClassificationProperties
|
||||||
attributes = {}
|
attributes = {}
|
||||||
@@ -138,9 +126,7 @@ class EditClassification(bpy.types.Operator):
|
|||||||
self.file,
|
self.file,
|
||||||
**{"classification": self.file.by_id(props.active_classification_id), "attributes": attributes},
|
**{"classification": self.file.by_id(props.active_classification_id), "attributes": attributes},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.disable_editing_classification()
|
bpy.ops.bim.disable_editing_classification()
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingClassificationReference(bpy.types.Operator):
|
class EnableEditingClassificationReference(bpy.types.Operator):
|
||||||
@@ -154,16 +140,7 @@ class EnableEditingClassificationReference(bpy.types.Operator):
|
|||||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||||
props = obj.BIMClassificationReferenceProperties
|
props = obj.BIMClassificationReferenceProperties
|
||||||
props.reference_attributes.clear()
|
props.reference_attributes.clear()
|
||||||
reference_data = Data.references[self.reference]
|
blenderbim.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.reference), props.reference_attributes)
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcClassificationReference").all_attributes():
|
|
||||||
if attribute.name() == "ReferencedSource":
|
|
||||||
continue
|
|
||||||
new = props.reference_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = reference_data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = "string"
|
|
||||||
new.string_value = "" if new.is_null else reference_data[attribute.name()]
|
|
||||||
props.active_reference_id = self.reference
|
props.active_reference_id = self.reference
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -180,41 +157,30 @@ class DisableEditingClassificationReference(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RemoveClassificationReference(bpy.types.Operator):
|
class RemoveClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.remove_classification_reference"
|
bl_idname = "bim.remove_classification_reference"
|
||||||
bl_label = "Remove Classification Reference"
|
bl_label = "Remove Classification Reference"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
reference: bpy.props.IntProperty()
|
reference: bpy.props.IntProperty()
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(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) if self.obj else context.active_object
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"classification.remove_reference",
|
"classification.remove_reference",
|
||||||
self.file,
|
self.file,
|
||||||
**{
|
reference=self.file.by_id(self.reference),
|
||||||
"reference": self.file.by_id(self.reference),
|
product=self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EditClassificationReference(bpy.types.Operator):
|
class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.edit_classification_reference"
|
bl_idname = "bim.edit_classification_reference"
|
||||||
bl_label = "Edit Classification Reference"
|
bl_label = "Edit Classification Reference"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(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) if self.obj else context.active_object
|
||||||
props = obj.BIMClassificationReferenceProperties
|
props = obj.BIMClassificationReferenceProperties
|
||||||
@@ -228,48 +194,37 @@ class EditClassificationReference(bpy.types.Operator):
|
|||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"classification.edit_reference",
|
"classification.edit_reference",
|
||||||
self.file,
|
self.file,
|
||||||
**{"reference": self.file.by_id(props.active_reference_id), "attributes": attributes},
|
reference=self.file.by_id(props.active_reference_id), attributes=attributes,
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.disable_editing_classification_reference()
|
bpy.ops.bim.disable_editing_classification_reference()
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddClassificationReference(bpy.types.Operator):
|
class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_classification_reference"
|
bl_idname = "bim.add_classification_reference"
|
||||||
bl_label = "Add Classification Reference"
|
bl_label = "Add Classification Reference"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
reference: bpy.props.IntProperty()
|
reference: bpy.props.IntProperty()
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(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) if self.obj else context.active_object
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
|
||||||
classification = None
|
|
||||||
|
|
||||||
props = context.scene.BIMClassificationProperties
|
props = context.scene.BIMClassificationProperties
|
||||||
classification_name = Data.library_classifications[int(props.available_classifications)]
|
classification = None
|
||||||
for classification_id, classification in Data.classifications.items():
|
classification_name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name
|
||||||
if classification["Name"] == classification_name:
|
for element in tool.Ifc.get().by_type("IfcClassification"):
|
||||||
classification = self.file.by_id(classification_id)
|
if element.Name == classification_name:
|
||||||
|
classification = element
|
||||||
break
|
break
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"classification.add_reference",
|
"classification.add_reference",
|
||||||
self.file,
|
self.file,
|
||||||
**{
|
reference=IfcStore.classification_file.by_id(self.reference),
|
||||||
"reference": Data.library_file.by_id(self.reference),
|
product=tool.Ifc.get_entity(obj),
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
classification=classification,
|
||||||
"classification": classification,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeClassificationLevel(bpy.types.Operator):
|
class ChangeClassificationLevel(bpy.types.Operator):
|
||||||
@@ -279,5 +234,27 @@ class ChangeClassificationLevel(bpy.types.Operator):
|
|||||||
parent_id: bpy.props.IntProperty()
|
parent_id: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
getReferences(self, context, parent_id=self.parent_id)
|
props = context.scene.BIMClassificationProperties
|
||||||
|
props.available_library_references.clear()
|
||||||
|
for reference in IfcStore.classification_file.by_id(self.parent_id).HasReferences:
|
||||||
|
new = props.available_library_references.add()
|
||||||
|
new.identification = reference.Identification or ""
|
||||||
|
new.name = reference.Name or ""
|
||||||
|
new.ifc_definition_id = reference.id()
|
||||||
|
new.has_references = bool(reference.HasReferences)
|
||||||
|
new.referenced_source
|
||||||
|
if reference.ReferencedSource.is_a("IfcClassificationReference"):
|
||||||
|
props.active_library_referenced_source = reference.ReferencedSource.ReferencedSource.id()
|
||||||
|
else:
|
||||||
|
props.active_library_referenced_source = 0
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingClassificationReferences(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.disable_editing_classification_references"
|
||||||
|
bl_label = "Disable Editing Classification References"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMClassificationProperties
|
||||||
|
props.available_library_references.clear()
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from ifcopenshell.api.classification.data import Data
|
from blenderbim.bim.module.classification.data import ClassificationsData
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -31,42 +32,10 @@ from bpy.props import (
|
|||||||
CollectionProperty,
|
CollectionProperty,
|
||||||
)
|
)
|
||||||
|
|
||||||
classification_enum = []
|
def get_available_classifications(self, context):
|
||||||
|
if not ClassificationsData.is_loaded:
|
||||||
|
ClassificationsData.load()
|
||||||
def purge():
|
return ClassificationsData.data["available_classifications"]
|
||||||
global classification_enum
|
|
||||||
classification_enum = []
|
|
||||||
|
|
||||||
|
|
||||||
def getClassifications(self, context):
|
|
||||||
global classification_enum
|
|
||||||
if len(classification_enum) < 1:
|
|
||||||
classification_enum.clear()
|
|
||||||
classification_enum.extend([(str(i), n, "") for i, n in Data.library_classifications.items()])
|
|
||||||
if classification_enum:
|
|
||||||
getReferences(self, context, parent_id=int(classification_enum[0][0]))
|
|
||||||
return classification_enum
|
|
||||||
|
|
||||||
|
|
||||||
def updateClassification(self, context):
|
|
||||||
getReferences(self, context, parent_id=int(self.available_classifications))
|
|
||||||
|
|
||||||
|
|
||||||
def getReferences(self, context, parent_id=None):
|
|
||||||
props = context.scene.BIMClassificationProperties
|
|
||||||
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 ""
|
|
||||||
new.name = reference.Name or ""
|
|
||||||
new.ifc_definition_id = reference.id()
|
|
||||||
new.has_references = bool(reference.HasReferences)
|
|
||||||
new.referenced_source
|
|
||||||
if reference.ReferencedSource.is_a("IfcClassificationReference"):
|
|
||||||
props.active_library_referenced_source = reference.ReferencedSource.ReferencedSource.id()
|
|
||||||
else:
|
|
||||||
props.active_library_referenced_source = 0
|
|
||||||
|
|
||||||
|
|
||||||
class ClassificationReference(PropertyGroup):
|
class ClassificationReference(PropertyGroup):
|
||||||
@@ -78,9 +47,7 @@ class ClassificationReference(PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
class BIMClassificationProperties(PropertyGroup):
|
class BIMClassificationProperties(PropertyGroup):
|
||||||
available_classifications: EnumProperty(
|
available_classifications: EnumProperty(items=get_available_classifications, name="Available Classifications")
|
||||||
items=getClassifications, name="Available Classifications", update=updateClassification
|
|
||||||
)
|
|
||||||
classification_attributes: CollectionProperty(name="Classification Attributes", type=Attribute)
|
classification_attributes: CollectionProperty(name="Classification Attributes", type=Attribute)
|
||||||
active_classification_id: IntProperty(name="Active Classification Id")
|
active_classification_id: IntProperty(name="Active Classification Id")
|
||||||
available_library_references: CollectionProperty(name="Available Library References", type=ClassificationReference)
|
available_library_references: CollectionProperty(name="Available Library References", type=ClassificationReference)
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import blenderbim.bim.helper
|
||||||
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.module.classification.prop as classification_prop
|
import blenderbim.bim.module.classification.prop as classification_prop
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.classification.data import Data
|
from blenderbim.bim.module.classification.data import ClassificationsData, ClassificationReferencesData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_classifications(Panel):
|
class BIM_PT_classifications(Panel):
|
||||||
@@ -33,15 +35,15 @@ class BIM_PT_classifications(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return IfcStore.get_file()
|
return tool.Ifc.get()
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not Data.is_loaded:
|
if not ClassificationsData.is_loaded:
|
||||||
Data.load(IfcStore.get_file())
|
ClassificationsData.load()
|
||||||
|
|
||||||
self.props = context.scene.BIMClassificationProperties
|
self.props = context.scene.BIMClassificationProperties
|
||||||
|
|
||||||
if Data.library_file:
|
if ClassificationsData.data["has_classification_file"]:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props, "available_classifications", text="")
|
row.prop(self.props, "available_classifications", text="")
|
||||||
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
||||||
@@ -51,33 +53,25 @@ class BIM_PT_classifications(Panel):
|
|||||||
row.label(text="No Active Classification Library")
|
row.label(text="No Active Classification Library")
|
||||||
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
||||||
|
|
||||||
for classification_id, classification in Data.classifications.items():
|
for classification in ClassificationsData.data["classifications"]:
|
||||||
if self.props.active_classification_id == classification_id:
|
if self.props.active_classification_id == classification["id"]:
|
||||||
self.draw_editable_ui(classification)
|
self.draw_editable_ui()
|
||||||
else:
|
else:
|
||||||
self.draw_ui(classification_id, classification)
|
self.draw_ui(classification)
|
||||||
|
|
||||||
def draw_editable_ui(self, classification):
|
def draw_editable_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props.classification_attributes.get("Name"), "string_value", text="", icon="ASSET_MANAGER")
|
row.operator("bim.edit_classification", text="Save changes", icon="CHECKMARK")
|
||||||
row.operator("bim.edit_classification", text="", icon="CHECKMARK")
|
|
||||||
row.operator("bim.disable_editing_classification", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_classification", text="", icon="CANCEL")
|
||||||
|
blenderbim.bim.helper.draw_attributes(self.props.classification_attributes, self.layout)
|
||||||
|
|
||||||
for attribute in self.props.classification_attributes:
|
def draw_ui(self, classification):
|
||||||
if attribute.name == "Name":
|
|
||||||
continue
|
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.prop(attribute, "string_value", text=attribute.name)
|
|
||||||
if attribute.is_optional:
|
|
||||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
|
||||||
|
|
||||||
def draw_ui(self, classification_id, classification):
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=classification["Name"], icon="ASSET_MANAGER")
|
row.label(text=classification["Name"], icon="ASSET_MANAGER")
|
||||||
if not self.props.active_classification_id:
|
if not self.props.active_classification_id:
|
||||||
op = row.operator("bim.enable_editing_classification", text="", icon="GREASEPENCIL")
|
op = row.operator("bim.enable_editing_classification", text="", icon="GREASEPENCIL")
|
||||||
op.classification = classification_id
|
op.classification = classification["id"]
|
||||||
row.operator("bim.remove_classification", text="", icon="X").classification = classification_id
|
row.operator("bim.remove_classification", text="", icon="X").classification = classification["id"]
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_classification_references(Panel):
|
class BIM_PT_classification_references(Panel):
|
||||||
@@ -93,74 +87,63 @@ class BIM_PT_classification_references(Panel):
|
|||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
if not context.active_object:
|
if not context.active_object:
|
||||||
return False
|
return False
|
||||||
if not IfcStore.get_element(context.active_object.BIMObjectProperties.ifc_definition_id):
|
return bool(tool.Ifc.get_entity(context.active_object))
|
||||||
return False
|
|
||||||
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
if not ClassificationReferencesData.is_loaded:
|
||||||
|
ClassificationReferencesData.load()
|
||||||
|
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
self.oprops = obj.BIMObjectProperties
|
self.oprops = obj.BIMObjectProperties
|
||||||
self.sprops = context.scene.BIMClassificationProperties
|
self.sprops = context.scene.BIMClassificationProperties
|
||||||
self.props = obj.BIMClassificationReferenceProperties
|
self.props = obj.BIMClassificationReferenceProperties
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
if not Data.is_loaded:
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
if self.oprops.ifc_definition_id not in Data.products:
|
|
||||||
Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id)
|
|
||||||
|
|
||||||
self.draw_add_ui(context)
|
self.draw_add_ui(context)
|
||||||
|
|
||||||
reference_ids = Data.products[self.oprops.ifc_definition_id]
|
if not ClassificationReferencesData.data["references"]:
|
||||||
if not reference_ids:
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="No References")
|
row.label(text="No References")
|
||||||
|
|
||||||
for reference_id in reference_ids:
|
for reference in ClassificationReferencesData.data["references"]:
|
||||||
reference = Data.references[reference_id]
|
if self.props.active_reference_id == reference["id"]:
|
||||||
if self.props.active_reference_id == reference_id:
|
self.draw_editable_ui()
|
||||||
self.draw_editable_ui(reference)
|
|
||||||
else:
|
else:
|
||||||
self.draw_ui(reference_id, reference)
|
self.draw_ui(reference)
|
||||||
|
|
||||||
def draw_add_ui(self, context):
|
def draw_add_ui(self, context):
|
||||||
if not classification_prop.getClassifications(self.sprops, context):
|
if not ClassificationReferencesData.data["is_available_classification_added"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
name = Data.library_classifications[int(self.sprops.available_classifications)]
|
|
||||||
if name in [c["Name"] for c in Data.classifications.values()]:
|
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.prop(self.sprops, "available_classifications", text="")
|
|
||||||
if self.sprops.active_library_referenced_source:
|
|
||||||
op = row.operator("bim.change_classification_level", text="", icon="FRAME_PREV")
|
|
||||||
op.parent_id = self.sprops.active_library_referenced_source
|
|
||||||
op = row.operator("bim.add_classification_reference", text="", icon="ADD")
|
|
||||||
op.reference = self.sprops.available_library_references[
|
|
||||||
self.sprops.active_library_reference_index
|
|
||||||
].ifc_definition_id
|
|
||||||
self.layout.template_list(
|
|
||||||
"BIM_UL_classifications",
|
|
||||||
"",
|
|
||||||
self.sprops,
|
|
||||||
"available_library_references",
|
|
||||||
self.sprops,
|
|
||||||
"active_library_reference_index",
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw_editable_ui(self, reference):
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props.reference_attributes.get("Name"), "string_value", text="", icon="ASSET_MANAGER")
|
row.prop(self.sprops, "available_classifications", text="")
|
||||||
row.operator("bim.edit_classification_reference", text="", icon="CHECKMARK")
|
if not self.sprops.available_library_references:
|
||||||
|
op = row.operator("bim.change_classification_level", text="", icon="IMPORT")
|
||||||
|
op.parent_id = int(self.sprops.available_classifications)
|
||||||
|
return
|
||||||
|
if self.sprops.active_library_referenced_source:
|
||||||
|
op = row.operator("bim.change_classification_level", text="", icon="FRAME_PREV")
|
||||||
|
op.parent_id = self.sprops.active_library_referenced_source
|
||||||
|
op = row.operator("bim.add_classification_reference", text="", icon="ADD")
|
||||||
|
op.reference = self.sprops.available_library_references[
|
||||||
|
self.sprops.active_library_reference_index
|
||||||
|
].ifc_definition_id
|
||||||
|
row.operator("bim.disable_editing_classification_references", text="", icon="CANCEL")
|
||||||
|
self.layout.template_list(
|
||||||
|
"BIM_UL_classifications",
|
||||||
|
"",
|
||||||
|
self.sprops,
|
||||||
|
"available_library_references",
|
||||||
|
self.sprops,
|
||||||
|
"active_library_reference_index",
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_editable_ui(self):
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.edit_classification_reference", text="Save changes", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_classification_reference", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_classification_reference", text="", icon="CANCEL")
|
||||||
|
blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
|
||||||
|
|
||||||
for attribute in self.props.reference_attributes:
|
def draw_ui(self, reference):
|
||||||
if attribute.name == "Name":
|
|
||||||
continue
|
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.prop(attribute, "string_value", text=attribute.name)
|
|
||||||
if attribute.is_optional:
|
|
||||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
|
||||||
|
|
||||||
def draw_ui(self, reference_id, reference):
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
if self.file.schema == "IFC2X3":
|
if self.file.schema == "IFC2X3":
|
||||||
name = reference["ItemReference"] or "No Identification"
|
name = reference["ItemReference"] or "No Identification"
|
||||||
@@ -170,8 +153,8 @@ class BIM_PT_classification_references(Panel):
|
|||||||
row.label(text=reference["Name"] or "")
|
row.label(text=reference["Name"] or "")
|
||||||
if not self.props.active_reference_id:
|
if not self.props.active_reference_id:
|
||||||
op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL")
|
op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL")
|
||||||
op.reference = reference_id
|
op.reference = reference["id"]
|
||||||
row.operator("bim.remove_classification_reference", text="", icon="X").reference = reference_id
|
row.operator("bim.remove_classification_reference", text="", icon="X").reference = reference["id"]
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_classifications(UIList):
|
class BIM_UL_classifications(UIList):
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
|
||||||
from blenderbim.bim.helper import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.pset_template.data import PsetTemplatesData
|
from blenderbim.bim.module.pset_template.data import PsetTemplatesData
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class Data:
|
|||||||
for classification in cls._file.by_type("IfcClassification"):
|
for classification in cls._file.by_type("IfcClassification"):
|
||||||
data = classification.get_info()
|
data = classification.get_info()
|
||||||
if cls._file.schema == "IFC2X3" and data["EditionDate"]:
|
if cls._file.schema == "IFC2X3" and data["EditionDate"]:
|
||||||
data["EditionDate"] = ifcopenshell.util.date(data.EditionDate).isoformat()
|
data["EditionDate"] = ifcopenshell.util.date.ifc2datetime(data["EditionDate"]).isoformat()
|
||||||
cls.classifications[classification.id()] = data
|
cls.classifications[classification.id()] = data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user