From d013d6ed098ded7f0890a7fc553c591a987bf54d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 28 Oct 2021 19:06:27 +1100 Subject: [PATCH] Resize object to storey now works for a variable number of storeys --- .../blenderbim/bim/module/misc/operator.py | 3 ++- .../blenderbim/bim/module/misc/prop.py | 1 + .../blenderbim/bim/module/misc/ui.py | 5 ++-- src/blenderbim/blenderbim/core/misc.py | 4 ++-- src/blenderbim/blenderbim/core/spatial.py | 20 ++++++++-------- src/blenderbim/blenderbim/core/tool.py | 2 +- src/blenderbim/blenderbim/tool/misc.py | 10 ++++---- src/blenderbim/test/bim/feature/misc.feature | 2 +- src/blenderbim/test/core/test_misc.py | 10 ++++---- src/blenderbim/test/tool/test_misc.py | 24 ++++++++++++++++--- 10 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/misc/operator.py b/src/blenderbim/blenderbim/bim/module/misc/operator.py index e7d77f9262..f1d5b630a9 100644 --- a/src/blenderbim/blenderbim/bim/module/misc/operator.py +++ b/src/blenderbim/blenderbim/bim/module/misc/operator.py @@ -117,6 +117,7 @@ class ResizeToStorey(bpy.types.Operator, Operator): bl_idname = "bim.resize_to_storey" bl_label = "Resize To Storey" bl_options = {"REGISTER", "UNDO"} + total_storeys: bpy.props.IntProperty() @classmethod def poll(cls, context): @@ -124,7 +125,7 @@ class ResizeToStorey(bpy.types.Operator, Operator): def _execute(self, context): for obj in context.selected_objects: - core.resize_to_storey(tool.Misc, obj=obj) + core.resize_to_storey(tool.Misc, obj=obj, total_storeys=self.total_storeys) class SplitAlongEdge(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/bim/module/misc/prop.py b/src/blenderbim/blenderbim/bim/module/misc/prop.py index 696c0c7c8d..7c2ddc54ea 100644 --- a/src/blenderbim/blenderbim/bim/module/misc/prop.py +++ b/src/blenderbim/blenderbim/bim/module/misc/prop.py @@ -32,6 +32,7 @@ from bpy.props import ( class BIMMiscProperties(PropertyGroup): + total_storeys: IntProperty(name="Total Storeys", default=1) override_colour: FloatVectorProperty( name="Override Colour", subtype="COLOR", default=(1, 0, 0, 1), min=0.0, max=1.0, size=4 ) diff --git a/src/blenderbim/blenderbim/bim/module/misc/ui.py b/src/blenderbim/blenderbim/bim/module/misc/ui.py index bdac446914..c3cb5300fe 100644 --- a/src/blenderbim/blenderbim/bim/module/misc/ui.py +++ b/src/blenderbim/blenderbim/bim/module/misc/ui.py @@ -38,7 +38,8 @@ class BIM_PT_misc_utilities(bpy.types.Panel): row.operator("bim.set_viewport_shadow_from_sun") row = layout.row() row.operator("bim.snap_spaces_together") - row = layout.row() - row.operator("bim.resize_to_storey") + row = layout.split(factor=0.2, align=True) + row.prop(props, "total_storeys", text="") + row.operator("bim.resize_to_storey").total_storeys = props.total_storeys row = layout.row() row.operator("bim.split_along_edge") diff --git a/src/blenderbim/blenderbim/core/misc.py b/src/blenderbim/blenderbim/core/misc.py index 5234194d6c..358f96d5ec 100644 --- a/src/blenderbim/blenderbim/core/misc.py +++ b/src/blenderbim/blenderbim/core/misc.py @@ -17,11 +17,11 @@ # along with BlenderBIM Add-on. If not, see . -def resize_to_storey(misc, obj=None): +def resize_to_storey(misc, obj=None, total_storeys=None): storey = misc.get_object_storey(obj) if not storey: return - height = misc.get_storey_height_in_si(storey) + height = misc.get_storey_height_in_si(storey, total_storeys) if not height: return misc.set_object_origin_to_bottom(obj) diff --git a/src/blenderbim/blenderbim/core/spatial.py b/src/blenderbim/blenderbim/core/spatial.py index a5e64a602c..8f8b538924 100644 --- a/src/blenderbim/blenderbim/core/spatial.py +++ b/src/blenderbim/blenderbim/core/spatial.py @@ -19,30 +19,30 @@ import blenderbim.core -def assign_container(ifc, collector, container, structure_obj=None, element_obj=None): - if not container.can_contain(structure_obj, element_obj): +def assign_container(ifc, collector, spatial, structure_obj=None, element_obj=None): + if not spatial.can_contain(structure_obj, element_obj): return rel = ifc.run( "spatial.assign_container", product=ifc.get_entity(element_obj), relating_structure=ifc.get_entity(structure_obj), ) - container.disable_editing(element_obj) + spatial.disable_editing(element_obj) collector.assign(element_obj) return rel -def enable_editing_container(container, obj=None): - container.enable_editing(obj) - container.import_containers() +def enable_editing_container(spatial, obj=None): + spatial.enable_editing(obj) + spatial.import_containers() -def disable_editing_container(container, obj=None): - container.disable_editing(obj) +def disable_editing_container(spatial, obj=None): + spatial.disable_editing(obj) -def change_spatial_level(container, parent=None): - container.import_containers(parent=parent) +def change_spatial_level(spatial, parent=None): + spatial.import_containers(parent=parent) def remove_container(ifc, collector, obj=None): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 1aa4a630e0..feefe4cac8 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -101,7 +101,7 @@ class Material: class Misc: def get_object_storey(cls, obj): pass def get_storey_elevation_in_si(cls, storey): pass - def get_storey_height_in_si(cls, storey): pass + def get_storey_height_in_si(cls, storey, total_storeys): pass def mark_object_as_edited(cls, obj): pass def move_object_to_elevation(cls, obj, elevation): pass def run_root_copy_class(cls, obj=None): pass diff --git a/src/blenderbim/blenderbim/tool/misc.py b/src/blenderbim/blenderbim/tool/misc.py index d68f0d997c..9f34572784 100644 --- a/src/blenderbim/blenderbim/tool/misc.py +++ b/src/blenderbim/blenderbim/tool/misc.py @@ -40,7 +40,7 @@ class Misc(blenderbim.core.tool.Misc): return elevation * unit_scale @classmethod - def get_storey_height_in_si(cls, storey): + def get_storey_height_in_si(cls, storey, total_storeys): building = ifcopenshell.util.element.get_aggregate(storey) related_objects = [] for rel in building.IsDecomposedBy: @@ -50,14 +50,12 @@ class Misc(blenderbim.core.tool.Misc): related_objects.append((element, ifcopenshell.util.placement.get_storey_elevation(element))) related_objects = sorted(related_objects, key=lambda e: e[1]) storey_elevation = None - next_storey_elevation = None - for related_object in related_objects: + for i, related_object in enumerate(related_objects): if related_object[0] == storey: storey_elevation = related_object[1] - elif storey_elevation is not None: - next_storey_elevation = related_object[1] break - if next_storey_elevation: + if i + total_storeys < len(related_objects): + next_storey_elevation = related_objects[i + total_storeys][1] unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) return (next_storey_elevation - storey_elevation) * unit_scale diff --git a/src/blenderbim/test/bim/feature/misc.feature b/src/blenderbim/test/bim/feature/misc.feature index fc59ccaed0..6f08795603 100644 --- a/src/blenderbim/test/bim/feature/misc.feature +++ b/src/blenderbim/test/bim/feature/misc.feature @@ -33,7 +33,7 @@ Scenario: Resize to storey And the object "IfcWall/Cube" is selected And the variable "storey" is "tool.Ifc.get().by_type('IfcBuildingStorey')[0].id()" And I press "bim.assign_container(structure={storey})" - When I press "bim.resize_to_storey" + When I press "bim.resize_to_storey(total_storeys=1)" Then nothing happens Scenario: Split along edge diff --git a/src/blenderbim/test/core/test_misc.py b/src/blenderbim/test/core/test_misc.py index 60a1046ed2..5f65c62867 100644 --- a/src/blenderbim/test/core/test_misc.py +++ b/src/blenderbim/test/core/test_misc.py @@ -24,21 +24,21 @@ class TestResizeToStorey: def test_run(self, misc): misc.get_object_storey("obj").should_be_called().will_return("storey") misc.get_storey_elevation_in_si("storey").should_be_called().will_return("elevation") - misc.get_storey_height_in_si("storey").should_be_called().will_return("height") + misc.get_storey_height_in_si("storey", 1).should_be_called().will_return("height") misc.set_object_origin_to_bottom("obj").should_be_called() misc.move_object_to_elevation("obj", "elevation").should_be_called() misc.scale_object_to_height("obj", "height").should_be_called() misc.mark_object_as_edited("obj").should_be_called() - subject.resize_to_storey(misc, obj="obj") + subject.resize_to_storey(misc, obj="obj", total_storeys=1) def test_doing_nothing_when_the_object_has_no_storey(self, misc): misc.get_object_storey("obj").should_be_called().will_return(None) - subject.resize_to_storey(misc, obj="obj") + subject.resize_to_storey(misc, obj="obj", total_storeys=1) def test_doing_nothing_when_the_storey_has_no_height(self, misc): misc.get_object_storey("obj").should_be_called().will_return("storey") - misc.get_storey_height_in_si("storey").should_be_called().will_return(None) - subject.resize_to_storey(misc, obj="obj") + misc.get_storey_height_in_si("storey", 1).should_be_called().will_return(None) + subject.resize_to_storey(misc, obj="obj", total_storeys=1) class TestSplitAlongEdge: diff --git a/src/blenderbim/test/tool/test_misc.py b/src/blenderbim/test/tool/test_misc.py index 9f2e47dd84..02ed0ca22d 100644 --- a/src/blenderbim/test/tool/test_misc.py +++ b/src/blenderbim/test/tool/test_misc.py @@ -88,7 +88,25 @@ class TestGetStoreyHeight(test.bim.bootstrap.NewFile): storey2.Elevation = 5000 ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey, relating_object=building) ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey2, relating_object=building) - assert subject.get_storey_height_in_si(storey) == 2.0 + assert subject.get_storey_height_in_si(storey, 1) == 2.0 + + def test_getting_a_double_storey_height(self): + ifc = ifcopenshell.file() + ifc.createIfcProject() + unit = ifcopenshell.api.run("unit.add_si_unit", ifc, prefix="MILLI") + ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit]) + tool.Ifc.set(ifc) + building = ifc.createIfcBuilding() + storey = ifc.createIfcBuildingStorey() + storey.Elevation = 3000 + storey2 = ifc.createIfcBuildingStorey() + storey2.Elevation = 5000 + storey3 = ifc.createIfcBuildingStorey() + storey3.Elevation = 9000 + ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey, relating_object=building) + ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey2, relating_object=building) + ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey3, relating_object=building) + assert subject.get_storey_height_in_si(storey, 2) == 6.0 def test_only_considering_storeys_in_the_same_building(self): ifc = ifcopenshell.file() @@ -99,7 +117,7 @@ class TestGetStoreyHeight(test.bim.bootstrap.NewFile): storey2 = ifc.createIfcBuildingStorey() storey2.Elevation = 5000 ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey, relating_object=building) - assert subject.get_storey_height_in_si(storey) is None + assert subject.get_storey_height_in_si(storey, 1) is None def test_returning_none_if_the_storey_height_is_undefined(self): ifc = ifcopenshell.file() @@ -107,7 +125,7 @@ class TestGetStoreyHeight(test.bim.bootstrap.NewFile): building = ifc.createIfcBuilding() storey = ifc.createIfcBuildingStorey() ifcopenshell.api.run("aggregate.assign_object", ifc, product=storey, relating_object=building) - assert subject.get_storey_height_in_si(storey) is None + assert subject.get_storey_height_in_si(storey, 1) is None class TestSetObjectOriginToBottom(test.bim.bootstrap.NewFile):