mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Resize object to storey now works for a variable number of storeys
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user