Minor fix & refactor, run black, fix pset optionality. See #1655.

This commit is contained in:
Dion Moult
2021-08-16 09:15:43 +10:00
parent 296bf0387d
commit 745411ee47
8 changed files with 48 additions and 50 deletions
+16 -16
View File
@@ -11,24 +11,24 @@ from blenderbim.bim.ifc import IfcStore
def draw_attributes(props, layout, copy_operator=None): def draw_attributes(props, layout, copy_operator=None):
for attribute in props: for attribute in props:
row = layout.row(align=True) row = layout.row(align=True)
draw_attribute(attribute, row) draw_attribute(attribute, row, copy_operator)
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})
def draw_attribute(attribute, layout): def draw_attribute(attribute, layout, copy_operator=None):
if not attribute.get_value_attr(): value_name = attribute.get_value_name()
if not value_name:
layout.label(text=attribute.name) layout.label(text=attribute.name)
else: return
layout.prop( layout.prop(
attribute, attribute,
attribute.get_value_attr(), value_name,
text=attribute.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): def import_attributes(ifc_class, props, data, callback=None):
@@ -66,6 +66,6 @@ def export_attributes(props, callback=None):
for prop in props: for prop in props:
is_handled_by_callback = callback(attributes, prop) if callback else False is_handled_by_callback = callback(attributes, prop) if callback else False
if is_handled_by_callback: if is_handled_by_callback:
continue # Our job is done continue # Our job is done
attributes[prop.name] = prop.get_value() attributes[prop.name] = prop.get_value()
return attributes return attributes
@@ -4,6 +4,7 @@ import ifcopenshell
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.attribute import ifcopenshell.util.attribute
import ifcopenshell.api import ifcopenshell.api
import blenderbim.bim.helper
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.georeference.data import Data from ifcopenshell.api.georeference.data import Data
from math import radians, degrees, atan, tan, cos, sin from math import radians, degrees, atan, tan, cos, sin
@@ -96,29 +97,13 @@ class EditGeoreferencing(bpy.types.Operator):
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
props = context.scene.BIMGeoreferenceProperties props = context.scene.BIMGeoreferenceProperties
projected_crs = {} projected_crs = blenderbim.bim.helper.export_attributes(props.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()
map_unit = "" map_unit = ""
if not props.is_map_unit_null: 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_unit = props.map_unit_si if props.map_unit_type == "IfcSIUnit" else props.map_unit_imperial
map_conversion = {} map_conversion = blenderbim.bim.helper.export_attributes(props.map_conversion, self.export_attributes)
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)
true_north = None true_north = None
if props.has_true_north: if props.has_true_north:
@@ -141,6 +126,11 @@ class EditGeoreferencing(bpy.types.Operator):
bpy.ops.bim.disable_editing_georeferencing() bpy.ops.bim.disable_editing_georeferencing()
return {"FINISHED"} 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): class SetBlenderGridNorth(bpy.types.Operator):
bl_idname = "bim.set_blender_grid_north" bl_idname = "bim.set_blender_grid_north"
@@ -655,7 +655,7 @@ class EditMaterialSetItem(bpy.types.Operator):
props = obj.BIMObjectMaterialProperties props = obj.BIMObjectMaterialProperties
product_data = Data.products[obj.BIMObjectProperties.ifc_definition_id] 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": if product_data["type"] == "IfcMaterialConstituentSet":
ifcopenshell.api.run( ifcopenshell.api.run(
@@ -680,7 +680,7 @@ class EditMaterialSetItem(bpy.types.Operator):
) )
Data.load_layers() Data.load_layers()
elif product_data["type"] == "IfcMaterialProfileSet" or product_data["type"] == "IfcMaterialProfileSetUsage": 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( ifcopenshell.api.run(
"material.edit_profile", "material.edit_profile",
self.file, self.file,
@@ -1,7 +1,12 @@
import os import os
import bpy import bpy
import json import json
import ifcpatch
try:
import ifcpatch
except:
print("IfcPatch not available")
from .helper import extract_docs from .helper import extract_docs
@@ -100,8 +100,9 @@ class EnablePsetEditing(bpy.types.Operator):
IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel") IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel")
) )
except: except:
# TODO: Occurs if the data type is something that exists in IFC4 and not in IFC2X3. To fully fix # TODO: Occurs if the data type is something that exists in
# this we need to generate the IFC2X3 pset template definitions. # IFC4 and not in IFC2X3. To fully fix this we need to
# generate the IFC2X3 pset template definitions.
continue continue
elif prop_template.TemplateType == "P_ENUMERATEDVALUE": elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
data_type = "enum" data_type = "enum"
@@ -116,6 +117,7 @@ class EnablePsetEditing(bpy.types.Operator):
new = self.props.properties.add() new = self.props.properties.add()
new.name = prop_template.Name new.name = prop_template.Name
new.is_null = data.get(prop_template.Name, None) is None new.is_null = data.get(prop_template.Name, None) is None
new.is_optional = True
new.data_type = data_type new.data_type = data_type
if data_type == "string": if data_type == "string":
@@ -140,6 +142,7 @@ class EnablePsetEditing(bpy.types.Operator):
new.set_value(value) new.set_value(value)
new.name = prop["Name"] new.name = prop["Name"]
new.is_null = value is None new.is_null = value is None
new.is_optional = True
new.set_value(new.get_value_default() if new.is_null else value) new.set_value(new.get_value_default() if new.is_null else value)
@@ -68,7 +68,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type):
def draw_psetqto_editable_ui(box, props, prop): def draw_psetqto_editable_ui(box, props, prop):
row = box.row() row = box.row(align=True)
draw_attribute(prop, row) draw_attribute(prop, row)
if ( if (
"length" in prop.name.lower() "length" in prop.name.lower()
@@ -279,7 +279,7 @@ class EditStructuralAnalysisModel(bpy.types.Operator):
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMStructuralProperties 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() self.file = IfcStore.get_file()
ifcopenshell.api.run( ifcopenshell.api.run(
"structural.edit_structural_analysis_model", "structural.edit_structural_analysis_model",
+9 -9
View File
@@ -127,7 +127,7 @@ class StrProperty(PropertyGroup):
def updateAttributeValue(self, context): 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 self.is_null = False
@@ -146,8 +146,8 @@ class Attribute(PropertyGroup):
def get_value(self): def get_value(self):
if self.is_null: if self.is_null:
return None 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): def get_value_default(self):
if self.data_type == "string": if self.data_type == "string":
return "" return ""
@@ -159,8 +159,8 @@ class Attribute(PropertyGroup):
return False return False
elif self.data_type == "enum": elif self.data_type == "enum":
return "0" return "0"
def get_value_attr(self): def get_value_name(self):
if self.data_type == "string": if self.data_type == "string":
return "string_value" return "string_value"
elif self.data_type == "boolean": elif self.data_type == "boolean":
@@ -171,21 +171,21 @@ class Attribute(PropertyGroup):
return "float_value" return "float_value"
elif self.data_type == "enum": elif self.data_type == "enum":
return "enum_value" return "enum_value"
def set_value(self, value): def set_value(self, value):
if isinstance(value, str): if isinstance(value, str):
self.data_type = "string" self.data_type = "string"
elif isinstance(value, float): elif isinstance(value, float):
self.data_type = "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" self.data_type = "boolean"
elif isinstance(value, int): elif isinstance(value, int):
self.data_type = "integer" self.data_type = "integer"
else: else:
self.data_type = "string" self.data_type = "string"
value = str(value) value = str(value)
setattr(self, self.get_value_attr(), value) setattr(self, self.get_value_name(), value)
class BIMProperties(PropertyGroup): class BIMProperties(PropertyGroup):
schema_dir: StringProperty( schema_dir: StringProperty(