mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Fix regression bug where you couldn't add a grid.
This commit is contained in:
@@ -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)
|
||||||
Reference in New Issue
Block a user