Fix regression bug where you couldn't add a grid.

This commit is contained in:
Dion Moult
2021-10-23 21:19:10 +11:00
parent 918915aeae
commit 7bccf10fec
8 changed files with 121 additions and 49 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ def draw_attribute(attribute, layout, copy_operator=None):
layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
if copy_operator: if copy_operator:
op = layout.operator(f"{copy_operator}", text="", icon="COPYDOWN") 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}) op.attribute_name = attribute.name
def import_attributes(ifc_class, props, data, callback=None): def import_attributes(ifc_class, props, data, callback=None):
@@ -0,0 +1,74 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 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 blenderbim.tool as tool
def refresh():
AttributesData.is_loaded = False
MaterialAttributesData.is_loaded = False
class AttributesData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"attributes": cls.attributes()}
cls.is_loaded = True
@classmethod
def attributes(cls):
results = []
element = tool.Ifc.get_entity(bpy.context.active_object)
data = element.get_info()
if hasattr(element, "GlobalId"):
excluded_keys = ["id", "type"]
else:
excluded_keys = ["type"]
for key, value in data.items():
if value is None or isinstance(value, ifcopenshell.entity_instance) or key in excluded_keys:
continue
if key == "id":
key = "STEP ID"
results.append({"name": key, "value": str(value)})
return results
class MaterialAttributesData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"attributes": cls.attributes()}
cls.is_loaded = True
@classmethod
def attributes(cls):
results = []
element = tool.Ifc.get_entity(bpy.context.active_object.active_material)
data = element.get_info()
for key, value in data.items():
if value is None or isinstance(value, ifcopenshell.entity_instance) or key in ["id", "type"]:
continue
results.append({"name": key, "value": str(value)})
return results
@@ -75,16 +75,13 @@ class DisableEditingAttributes(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class EditAttributes(bpy.types.Operator): class EditAttributes(bpy.types.Operator, Operator):
bl_idname = "bim.edit_attributes" bl_idname = "bim.edit_attributes"
bl_label = "Edit Attributes" bl_label = "Edit Attributes"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
obj_type: bpy.props.StringProperty() obj_type: bpy.props.StringProperty()
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()
if self.obj_type == "Object": if self.obj_type == "Object":
@@ -16,17 +16,16 @@
# 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
from bpy.types import Panel from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.attribute.data import Data from blenderbim.bim.module.attribute.data import AttributesData, MaterialAttributesData
def draw_ui(context, layout, obj_type): def draw_ui(context, layout, obj_type, attributes):
obj = context.active_object if obj_type == "Object" else context.active_object.active_material obj = context.active_object if obj_type == "Object" else context.active_object.active_material
oprops = obj.BIMObjectProperties oprops = obj.BIMObjectProperties
props = obj.BIMAttributeProperties props = obj.BIMAttributeProperties
if oprops.ifc_definition_id not in Data.products:
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
if props.is_editing_attributes: if props.is_editing_attributes:
row = layout.row(align=True) row = layout.row(align=True)
@@ -37,49 +36,17 @@ def draw_ui(context, layout, obj_type):
op.obj_type = obj_type op.obj_type = obj_type
op.obj = obj.name op.obj = obj.name
for attribute in Data.products[oprops.ifc_definition_id]: blenderbim.bim.helper.draw_attributes(props.attributes, layout, copy_operator="bim.copy_attribute_to_selection")
if attribute["type"] == "entity":
continue
row = layout.row(align=True)
blender_attribute = props.attributes.get(attribute["name"])
if attribute["type"] == "string" or attribute["type"] == "list":
row.prop(blender_attribute, "string_value", text=attribute["name"])
elif attribute["type"] == "integer":
row.prop(blender_attribute, "int_value", text=attribute["name"])
elif attribute["type"] == "float":
row.prop(blender_attribute, "float_value", text=attribute["name"])
elif attribute["type"] == "enum":
row.prop(blender_attribute, "enum_value", text=attribute["name"])
if attribute["name"] == "GlobalId":
row.operator("bim.generate_global_id", icon="FILE_REFRESH", text="")
if attribute["is_optional"]:
row.prop(
blender_attribute,
"is_null",
icon="RADIOBUT_OFF" if blender_attribute.is_null else "RADIOBUT_ON",
text="",
)
if attribute["name"] != "GlobalId":
op = row.operator("bim.copy_attribute_to_selection", icon="COPYDOWN", text="")
op.attribute_name = attribute["name"]
else: else:
row = layout.row() row = layout.row()
op = row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit") op = row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit")
op.obj_type = obj_type op.obj_type = obj_type
op.obj = obj.name op.obj = obj.name
if "GlobalId" not in [a["name"] for a in Data.products[oprops.ifc_definition_id]]: for attribute in attributes:
row = layout.row(align=True)
row.label(text="STEP ID")
row.label(text=str(oprops.ifc_definition_id))
for attribute in Data.products[oprops.ifc_definition_id]:
if attribute["value"] is None or attribute["type"] == "entity":
continue
row = layout.row(align=True) row = layout.row(align=True)
row.label(text=attribute["name"]) row.label(text=attribute["name"])
row.label(text=str(attribute["value"])) row.label(text=attribute["value"])
# TODO: reimplement, see #1222 # TODO: reimplement, see #1222
# if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name: # if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
@@ -102,7 +69,9 @@ class BIM_PT_object_attributes(Panel):
return bool(context.active_object.BIMObjectProperties.ifc_definition_id) return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
def draw(self, context): def draw(self, context):
draw_ui(context, self.layout, "Object") if not AttributesData.is_loaded:
AttributesData.load()
draw_ui(context, self.layout, "Object", AttributesData.data["attributes"])
class BIM_PT_material_attributes(Panel): class BIM_PT_material_attributes(Panel):
@@ -122,4 +91,6 @@ class BIM_PT_material_attributes(Panel):
return False return False
def draw(self, context): def draw(self, context):
draw_ui(context, self.layout, "Material") if not MaterialAttributesData.is_loaded:
MaterialAttributesData.load()
draw_ui(context, self.layout, "Material", MaterialAttributesData.data["attributes"])
@@ -18,6 +18,8 @@
import bpy import bpy
import ifcopenshell.api import ifcopenshell.api
import blenderbim.core.spatial
import blenderbim.tool as tool
from bpy.types import Operator from bpy.types import Operator
from bpy.props import FloatProperty, IntProperty from bpy.props import FloatProperty, IntProperty
from mathutils import Vector from mathutils import Vector
@@ -51,8 +53,8 @@ def add_object(self, context):
if has_site_collection: if has_site_collection:
site_obj = bpy.data.objects.get(grandchild.name) site_obj = bpy.data.objects.get(grandchild.name)
if site_obj and site_obj.BIMObjectProperties.ifc_definition_id: if site_obj and site_obj.BIMObjectProperties.ifc_definition_id:
bpy.ops.bim.assign_container( blenderbim.core.spatial.assign_container(
relating_structure=site_obj.BIMObjectProperties.ifc_definition_id, related_element=obj.name tool.Ifc, tool.Collector, tool.Spatial, structure_obj=site_obj, element_obj=obj
) )
axes_collection = bpy.data.collections.new("UAxes") axes_collection = bpy.data.collections.new("UAxes")
@@ -26,3 +26,14 @@ Scenario: Add type instance - add from an empty
And I set "scene.BIMTypeProperties.relating_type" to "{empty}" And I set "scene.BIMTypeProperties.relating_type" to "{empty}"
When I press "bim.add_type_instance" When I press "bim.add_type_instance"
Then the object "IfcWall/Instance" exists Then the object "IfcWall/Instance" exists
Scenario: Add grid
Given an empty IFC project
When I press "mesh.add_grid"
Then the object "IfcGrid/Grid" is an "IfcGrid"
And the object "IfcGridAxis/A" is an "IfcGridAxis"
And the object "IfcGridAxis/B" is an "IfcGridAxis"
And the object "IfcGridAxis/C" is an "IfcGridAxis"
And the object "IfcGridAxis/01" is an "IfcGridAxis"
And the object "IfcGridAxis/02" is an "IfcGridAxis"
And the object "IfcGridAxis/03" is an "IfcGridAxis"
@@ -12,7 +12,7 @@ class Usecase:
def execute(self): def execute(self):
element = self.file.create_entity( element = self.file.create_entity(
"IfcGridAxis", **{"axis_tag": self.settings["axis_tag"], "SameSense": self.settings["same_sense"]} "IfcGridAxis", **{"AxisTag": self.settings["axis_tag"], "SameSense": self.settings["same_sense"]}
) )
axes = list(getattr(self.settings["grid"], self.settings["uvw_axes"]) or []) axes = list(getattr(self.settings["grid"], self.settings["uvw_axes"]) or [])
axes.append(element) axes.append(element)
@@ -0,0 +1,17 @@
import test.bootstrap
import ifcopenshell.api
class TestCreateGridAxis(test.bootstrap.IFC4):
def test_run(self):
grid = self.file.createIfcGrid()
axis = ifcopenshell.api.run(
"grid.create_grid_axis", self.file, axis_tag="axis_tag", same_sense=True, uvw_axes="UAxes", grid=grid
)
assert axis.AxisTag == "axis_tag"
assert axis.SameSense is True
assert grid.UAxes == (axis,)
axis2 = ifcopenshell.api.run(
"grid.create_grid_axis", self.file, axis_tag="axis_tag", same_sense=True, uvw_axes="UAxes", grid=grid
)
assert grid.UAxes == (axis,axis2)