diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 6a16d145c6..83306ecd3f 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -501,7 +501,7 @@ class IfcImporter: shape = ifcopenshell.geom.create_shape(self.settings_2d, axis.AxisCurve) mesh = self.create_mesh(axis, shape) obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh) - obj.BIMObjectProperties.ifc_definition_id = axis.id() + self.link_element(axis, obj) obj.matrix_world = grid_obj.matrix_world grid_collection.objects.link(obj) @@ -1208,6 +1208,8 @@ class IfcImporter: def place_object_in_decomposition_collection(self, element, obj): if element.is_a("IfcProject"): return + elif element.is_a("IfcGridAxis"): + return elif element.GlobalId in self.collections: return self.collections[element.GlobalId].objects.link(obj) elif getattr(element, "Decomposes", None): @@ -1219,6 +1221,8 @@ class IfcImporter: def place_object_in_spatial_decomposition_collection(self, element, obj): if element.is_a("IfcProject"): return + elif element.is_a("IfcGridAxis"): + return elif element.GlobalId in self.collections: return self.collections[element.GlobalId].objects.link(obj) elif element.is_a("IfcTypeObject"): diff --git a/src/blenderbim/blenderbim/tool/collector.py b/src/blenderbim/blenderbim/tool/collector.py index 8ff5a7c9e5..0b8b9eb7e1 100644 --- a/src/blenderbim/blenderbim/tool/collector.py +++ b/src/blenderbim/blenderbim/tool/collector.py @@ -53,29 +53,38 @@ class Collector(blenderbim.core.tool.Collector): @classmethod def _get_own_collection(cls, element, obj): if element.is_a("IfcProject"): - collection = bpy.data.collections.get(obj.name) - if not collection: - collection = bpy.data.collections.new(obj.name) - return collection + return bpy.data.collections.get(obj.name, bpy.data.collections.new(obj.name)) if tool.Ifc.get_schema() == "IFC2X3": if element.is_a("IfcSpatialStructureElement"): - collection = bpy.data.collections.get(obj.name) - if not collection: - collection = bpy.data.collections.new(obj.name) - return collection + return bpy.data.collections.get(obj.name, bpy.data.collections.new(obj.name)) else: if element.is_a("IfcSpatialElement"): - collection = bpy.data.collections.get(obj.name) - if not collection: - collection = bpy.data.collections.new(obj.name) - return collection + return bpy.data.collections.get(obj.name, bpy.data.collections.new(obj.name)) - if element.IsDecomposedBy: - collection = bpy.data.collections.get(obj.name) - if not collection: - collection = bpy.data.collections.new(obj.name) - return collection + if element.is_a("IfcGrid"): + return bpy.data.collections.get(obj.name, bpy.data.collections.new(obj.name)) + + if element.is_a("IfcGridAxis"): + if element.PartOfU: + grid = element.PartOfU[0] + axes = "UAxes" + elif element.PartOfV: + grid = element.PartOfV[0] + axes = "VAxes" + elif element.PartOfW: + grid = element.PartOfW[0] + axes = "WAxes" + grid_obj = tool.Ifc.get_object(grid) + if grid_obj: + grid_col = bpy.data.collections.get(grid_obj.name) + axes_col = [c for c in grid_col.children if axes in c.name] + if axes_col: + return axes_col[0] + return bpy.data.collections.new(axes) + + if getattr(element, "IsDecomposedBy", None): + return bpy.data.collections.get(obj.name, bpy.data.collections.new(obj.name)) @classmethod def _get_collection(cls, element, obj): @@ -95,6 +104,20 @@ class Collector(blenderbim.core.tool.Collector): project_obj.users_collection[0].children.link(collection) return collection + if element.is_a("IfcGridAxis"): + if element.PartOfU: + grid = element.PartOfU[0] + axes = "UAxes" + elif element.PartOfV: + grid = element.PartOfV[0] + axes = "VAxes" + elif element.PartOfW: + grid = element.PartOfW[0] + axes = "WAxes" + grid_obj = tool.Ifc.get_object(grid) + if grid_obj: + return bpy.data.collections.get(grid_obj.name) + aggregate = ifcopenshell.util.element.get_aggregate(element) if aggregate: aggregate_obj = tool.Ifc.get_object(aggregate) diff --git a/src/blenderbim/blenderbim/tool/spatial.py b/src/blenderbim/blenderbim/tool/spatial.py index 6c21bd0050..b1f5389492 100644 --- a/src/blenderbim/blenderbim/tool/spatial.py +++ b/src/blenderbim/blenderbim/tool/spatial.py @@ -37,7 +37,7 @@ class Spatial(blenderbim.core.tool.Spatial): else: if not structure.is_a("IfcSpatialElement"): return False - if not element.is_a("IfcElement"): + if not hasattr(element, "ContainedInStructure"): return False return True diff --git a/src/blenderbim/test/tool/test_collector.py b/src/blenderbim/test/tool/test_collector.py index 5eec59cfc5..920c24bc01 100644 --- a/src/blenderbim/test/tool/test_collector.py +++ b/src/blenderbim/test/tool/test_collector.py @@ -178,3 +178,39 @@ class TestAssign(NewFile): subject.assign(element_obj) assert element_obj.users_collection[0].name == "IfcOpeningElements" assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcOpeningElements") + + def test_in_decomposition_mode_grids_are_placed_in_their_own_collection(self): + bpy.ops.bim.create_project() + element_obj = bpy.data.objects.new("IfcGrid/Name", None) + element = tool.Ifc.get().createIfcGrid() + tool.Ifc.link(element, element_obj) + ifcopenshell.api.run( + "spatial.assign_container", + tool.Ifc.get(), + product=element, + relating_structure=tool.Ifc.get().by_type("IfcSite")[0], + ) + bpy.context.scene.collection.objects.link(element_obj) + subject.assign(element_obj) + assert element_obj.users_collection[0].name == "IfcGrid/Name" + assert bpy.data.collections.get("IfcSite/My Site").children.get("IfcGrid/Name") + + def test_in_decomposition_mode_grids_axes_are_placed_in_an_axis_collection_of_the_grid(self): + bpy.ops.bim.create_project() + element_obj = bpy.data.objects.new("IfcGrid/Name", None) + axis_obj = bpy.data.objects.new("IfcGrid/Name", None) + axis = tool.Ifc.get().createIfcGridAxis() + element = tool.Ifc.get().createIfcGrid(UAxes=[axis]) + tool.Ifc.link(element, element_obj) + tool.Ifc.link(axis, axis_obj) + ifcopenshell.api.run( + "spatial.assign_container", + tool.Ifc.get(), + product=element, + relating_structure=tool.Ifc.get().by_type("IfcSite")[0], + ) + bpy.context.scene.collection.objects.link(element_obj) + subject.assign(element_obj) + subject.assign(axis_obj) + assert axis_obj.users_collection[0].name == "UAxes" + assert bpy.data.collections.get("IfcGrid/Name").children.get("UAxes") diff --git a/src/blenderbim/test/tool/test_spatial.py b/src/blenderbim/test/tool/test_spatial.py index c70fa7e750..84d50ef787 100644 --- a/src/blenderbim/test/tool/test_spatial.py +++ b/src/blenderbim/test/tool/test_spatial.py @@ -80,6 +80,17 @@ class TestCanContain(NewFile): tool.Ifc.link(element, element_obj) assert subject.can_contain(structure_obj, element_obj) is False + def test_other_non_elements_that_have_a_contained_in_structure_attribute_can_be_contained(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + structure = ifc.createIfcSite() + structure_obj = bpy.data.objects.new("Object", None) + tool.Ifc.link(structure, structure_obj) + element = ifc.createIfcGrid() + element_obj = bpy.data.objects.new("Object", None) + tool.Ifc.link(element, element_obj) + assert subject.can_contain(structure_obj, element_obj) is True + class TestDisableEditing(NewFile): def test_run(self):