diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 8eef8750c1..ba6d146bfe 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -11,24 +11,24 @@ from blenderbim.bim.ifc import IfcStore def draw_attributes(props, layout, copy_operator=None): for attribute in props: row = layout.row(align=True) - draw_attribute(attribute, row) - value = attribute.get_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): - if not attribute.get_value_attr(): +def draw_attribute(attribute, layout, copy_operator=None): + value_name = attribute.get_value_name() + if not value_name: layout.label(text=attribute.name) - else: - layout.prop( - attribute, - attribute.get_value_attr(), - 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): @@ -66,6 +66,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 + continue # Our job is done attributes[prop.name] = prop.get_value() return attributes diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index ff1970152b..020537c687 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -4,6 +4,7 @@ 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 @@ -96,29 +97,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()) - projected_crs[attribute.name()] = blender_attribute.get_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: @@ -141,6 +126,11 @@ 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": + attributes[prop.name] = float(prop.string_value) + return True + class SetBlenderGridNorth(bpy.types.Operator): bl_idname = "bim.set_blender_grid_north" diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index 1fde8c931a..349e8991e3 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -655,7 +655,7 @@ class EditMaterialSetItem(bpy.types.Operator): props = obj.BIMObjectMaterialProperties product_data = Data.products[obj.BIMObjectProperties.ifc_definition_id] - attributes = {attribute.name: attribute.get_value() for attribute in props.material_set_item_attributes} + attributes = blenderbim.bim.helper.export_attributes(props.material_set_item_attributes) if product_data["type"] == "IfcMaterialConstituentSet": ifcopenshell.api.run( @@ -680,7 +680,7 @@ class EditMaterialSetItem(bpy.types.Operator): ) Data.load_layers() elif product_data["type"] == "IfcMaterialProfileSet" or product_data["type"] == "IfcMaterialProfileSetUsage": - profile_attributes = {attr.name: attr.get_value() for attr in props.material_set_item_profile_attributes} + 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/patch/operator.py b/src/blenderbim/blenderbim/bim/module/patch/operator.py index 5abf2b3a3b..e59e3e04af 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/operator.py +++ b/src/blenderbim/blenderbim/bim/module/patch/operator.py @@ -1,7 +1,12 @@ import os import bpy import json -import ifcpatch + +try: + import ifcpatch +except: + print("IfcPatch not available") + from .helper import extract_docs diff --git a/src/blenderbim/blenderbim/bim/module/pset/operator.py b/src/blenderbim/blenderbim/bim/module/pset/operator.py index b34586c14b..2ef9b1cf01 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/operator.py @@ -100,8 +100,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 +117,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": @@ -140,6 +142,7 @@ class EnablePsetEditing(bpy.types.Operator): new.set_value(value) new.name = prop["Name"] new.is_null = value is None + new.is_optional = True new.set_value(new.get_value_default() if new.is_null else value) diff --git a/src/blenderbim/blenderbim/bim/module/pset/ui.py b/src/blenderbim/blenderbim/bim/module/pset/ui.py index 53fae14dda..6fe7e91593 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset/ui.py @@ -68,7 +68,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type): def draw_psetqto_editable_ui(box, props, prop): - row = box.row() + row = box.row(align=True) draw_attribute(prop, row) if ( "length" in prop.name.lower() diff --git a/src/blenderbim/blenderbim/bim/module/structural/operator.py b/src/blenderbim/blenderbim/bim/module/structural/operator.py index 38133c4abc..58864171c7 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/operator.py +++ b/src/blenderbim/blenderbim/bim/module/structural/operator.py @@ -279,7 +279,7 @@ class EditStructuralAnalysisModel(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMStructuralProperties - attributes = {attribute.name: attribute.get_value() for attribute in props.structural_analysis_model_attributes} + attributes = blenderbim.bim.helper.export_attributes(props.structural_analysis_model_attributes) self.file = IfcStore.get_file() ifcopenshell.api.run( "structural.edit_structural_analysis_model", diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index 0e891b744f..613646f6e4 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -127,7 +127,7 @@ class StrProperty(PropertyGroup): def updateAttributeValue(self, context): - if getattr(self, str(self.get_value_attr()), None): # Do not use get_value since it returns None if is_null is True + if getattr(self, str(self.get_value_name()), None): # Do not use get_value since it returns None if is_null is True self.is_null = False @@ -146,8 +146,8 @@ class Attribute(PropertyGroup): def get_value(self): if self.is_null: return None - return getattr(self, str(self.get_value_attr()), None) - + return getattr(self, str(self.get_value_name()), None) + def get_value_default(self): if self.data_type == "string": return "" @@ -159,8 +159,8 @@ class Attribute(PropertyGroup): return False elif self.data_type == "enum": return "0" - - def get_value_attr(self): + + def get_value_name(self): if self.data_type == "string": return "string_value" elif self.data_type == "boolean": @@ -171,21 +171,21 @@ class Attribute(PropertyGroup): return "float_value" elif self.data_type == "enum": return "enum_value" - + def set_value(self, value): if isinstance(value, str): self.data_type = "string" elif isinstance(value, float): self.data_type = "float" - elif isinstance(value, bool): # Make sure this is evaluated BEFORE integer + elif isinstance(value, bool): # Make sure this is evaluated BEFORE integer self.data_type = "boolean" elif isinstance(value, int): self.data_type = "integer" else: self.data_type = "string" value = str(value) - setattr(self, self.get_value_attr(), value) - + setattr(self, self.get_value_name(), value) + class BIMProperties(PropertyGroup): schema_dir: StringProperty(