mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
See #1676. You can now duplicate space boundaries.
This commit is contained in:
@@ -491,8 +491,7 @@ class ShowBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
for rel in element.BoundedBy or []:
|
||||
boundary_obj = loader.load_boundary(rel, obj)
|
||||
new = props.boundaries.add()
|
||||
new.obj = boundary_obj
|
||||
tool.Boundary.decorate_boundary(boundary_obj)
|
||||
BoundaryDecorator.install(bpy.context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -527,6 +527,8 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
array_pset = tool.Ifc.get().by_id(array_pset["id"])
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=new, pset=array_pset)
|
||||
old_to_new[tool.Ifc.get_entity(obj)] = [new]
|
||||
if new.is_a("IfcRelSpaceBoundary"):
|
||||
tool.Boundary.decorate_boundary(new_obj)
|
||||
# Recreate decompositions
|
||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||
blenderbim.bim.handler.purge_module_data()
|
||||
|
||||
@@ -21,6 +21,10 @@ def copy_class(ifc, collector, geometry, root, obj=None):
|
||||
element = ifc.get_entity(obj)
|
||||
if not element:
|
||||
return
|
||||
if root.is_element_a(element, "IfcRelSpaceBoundary"):
|
||||
new = ifc.run("boundary.copy_boundary", boundary=element)
|
||||
ifc.link(new, obj)
|
||||
return new
|
||||
representation = root.get_object_representation(obj)
|
||||
new = ifc.run("root.copy_class", product=element)
|
||||
ifc.link(new, obj)
|
||||
@@ -38,7 +42,7 @@ def copy_class(ifc, collector, geometry, root, obj=None):
|
||||
geometry.link(new_representation, data)
|
||||
root.assign_body_styles(new, obj)
|
||||
collector.assign(obj)
|
||||
if root.is_opening_element(new):
|
||||
if root.is_element_a(new, "IfcOpeningElement"):
|
||||
root.add_tracked_opening(obj)
|
||||
return new
|
||||
|
||||
|
||||
@@ -606,7 +606,7 @@ class Root:
|
||||
def get_object_name(cls, obj): pass
|
||||
def get_object_representation(cls, obj): pass
|
||||
def get_representation_context(cls, representation): pass
|
||||
def is_opening_element(cls, element): pass
|
||||
def is_element_a(cls, element, ifc_class): pass
|
||||
def link_object_data(cls, source_obj, destination_obj): pass
|
||||
def recreate_decompositions(cls, relationships, old_to_new): pass
|
||||
def run_geometry_add_representation(cls, obj=None, context=None, ifc_representation_class=None, profile_set_usage=None): pass
|
||||
|
||||
@@ -70,3 +70,9 @@ class Boundary(blenderbim.core.tool.Boundary):
|
||||
translation = obj.matrix_world.translation - space.matrix_world.translation
|
||||
obj.data.transform(mathutils.Matrix.Translation(translation))
|
||||
obj.matrix_world = space.matrix_world
|
||||
|
||||
@classmethod
|
||||
def decorate_boundary(cls, obj):
|
||||
new = bpy.context.scene.BIMBoundaryProperties.boundaries.add()
|
||||
new.obj = obj
|
||||
obj.show_in_front = True
|
||||
|
||||
@@ -119,8 +119,8 @@ class Root(blenderbim.core.tool.Root):
|
||||
return representation.ContextOfItems
|
||||
|
||||
@classmethod
|
||||
def is_opening_element(cls, element):
|
||||
return element.is_a("IfcOpeningElement")
|
||||
def is_element_a(cls, element, ifc_class):
|
||||
return element.is_a(ifc_class)
|
||||
|
||||
@classmethod
|
||||
def link_object_data(cls, source_obj, destination_obj):
|
||||
|
||||
@@ -28,6 +28,7 @@ class TestCopyClass:
|
||||
|
||||
def test_copy_with_new_geometry_derived_from_the_type(self, ifc, collector, root):
|
||||
ifc.get_entity("obj").should_be_called().will_return("original_element")
|
||||
root.is_element_a("original_element", "IfcRelSpaceBoundary").should_be_called().will_return(False)
|
||||
root.get_object_representation("obj").should_be_called().will_return("representation")
|
||||
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
|
||||
ifc.link("element", "obj").should_be_called()
|
||||
@@ -37,7 +38,7 @@ class TestCopyClass:
|
||||
ifc.get_object("type").should_be_called().will_return("type_obj")
|
||||
root.link_object_data("type_obj", "obj").should_be_called()
|
||||
collector.assign("obj").should_be_called()
|
||||
root.is_opening_element("element").should_be_called().will_return(False)
|
||||
root.is_element_a("element", "IfcOpeningElement").should_be_called().will_return(False)
|
||||
subject.copy_class(ifc, collector, geometry, root, obj="obj")
|
||||
|
||||
def test_copy_with_new_geometry_copied_from_the_old(self, ifc, collector, geometry, root):
|
||||
@@ -45,6 +46,7 @@ class TestCopyClass:
|
||||
# copied. This was faster (though I cannot recreate it now) but had the
|
||||
# bigger problem of not preserving non-mesh geometry and openings.
|
||||
ifc.get_entity("obj").should_be_called().will_return("original_element")
|
||||
root.is_element_a("original_element", "IfcRelSpaceBoundary").should_be_called().will_return(False)
|
||||
root.get_object_representation("obj").should_be_called().will_return("representation")
|
||||
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
|
||||
ifc.link("element", "obj").should_be_called()
|
||||
@@ -60,22 +62,24 @@ class TestCopyClass:
|
||||
root.assign_body_styles("element", "obj").should_be_called()
|
||||
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
|
||||
collector.assign("obj").should_be_called()
|
||||
root.is_opening_element("element").should_be_called().will_return(False)
|
||||
root.is_element_a("element", "IfcOpeningElement").should_be_called().will_return(False)
|
||||
subject.copy_class(ifc, collector, geometry, root, obj="obj")
|
||||
|
||||
def test_copy_with_no_new_geometry(self, ifc, collector, geometry, root):
|
||||
ifc.get_entity("obj").should_be_called().will_return("original_element")
|
||||
root.is_element_a("original_element", "IfcRelSpaceBoundary").should_be_called().will_return(False)
|
||||
root.get_object_representation("obj").should_be_called().will_return(None)
|
||||
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
|
||||
ifc.link("element", "obj").should_be_called()
|
||||
root.get_element_type("element").should_be_called().will_return("type")
|
||||
root.does_type_have_representations("type").should_be_called().will_return(False)
|
||||
collector.assign("obj").should_be_called()
|
||||
root.is_opening_element("element").should_be_called().will_return(False)
|
||||
root.is_element_a("element", "IfcOpeningElement").should_be_called().will_return(False)
|
||||
subject.copy_class(ifc, collector, geometry, root, obj="obj")
|
||||
|
||||
def test_copied_openings_are_tracked_for_special_visualiation(self, ifc, collector, root):
|
||||
def test_copied_openings_are_tracked_for_special_visualiation(self, ifc, collector, geometry, root):
|
||||
ifc.get_entity("obj").should_be_called().will_return("original_element")
|
||||
root.is_element_a("original_element", "IfcRelSpaceBoundary").should_be_called().will_return(False)
|
||||
root.get_object_representation("obj").should_be_called().will_return(None)
|
||||
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
|
||||
ifc.link("element", "obj").should_be_called()
|
||||
@@ -85,10 +89,17 @@ class TestCopyClass:
|
||||
ifc.get_object("type").should_be_called().will_return("type_obj")
|
||||
root.link_object_data("type_obj", "obj").should_be_called()
|
||||
collector.assign("obj").should_be_called()
|
||||
root.is_opening_element("element").should_be_called().will_return(True)
|
||||
root.is_element_a("element", "IfcOpeningElement").should_be_called().will_return(True)
|
||||
root.add_tracked_opening("obj").should_be_called()
|
||||
subject.copy_class(ifc, collector, geometry, root, obj="obj")
|
||||
|
||||
def test_copying_boundaries_are_dealt_with_specially(self, ifc, collector, geometry, root):
|
||||
ifc.get_entity("obj").should_be_called().will_return("original_element")
|
||||
root.is_element_a("original_element", "IfcRelSpaceBoundary").should_be_called().will_return(True)
|
||||
ifc.run("boundary.copy_boundary", boundary="original_element").should_be_called().will_return("element")
|
||||
ifc.link("element", "obj").should_be_called()
|
||||
assert subject.copy_class(ifc, collector, geometry, root, obj="obj") == "element"
|
||||
|
||||
|
||||
class TestAssignClass:
|
||||
def test_do_nothing_if_already_assigned(self, ifc, collector, root):
|
||||
|
||||
@@ -132,11 +132,11 @@ class TestGetRepresentationContext(NewFile):
|
||||
assert subject.get_representation_context(representation) == context
|
||||
|
||||
|
||||
class TestIsOpeningElement(NewFile):
|
||||
class TestIsElementA(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
assert subject.is_opening_element(ifc.createIfcWall()) is False
|
||||
assert subject.is_opening_element(ifc.createIfcOpeningElement()) is True
|
||||
assert subject.is_a(ifc.createIfcWall(), "IfcSlab") is False
|
||||
assert subject.is_a(ifc.createIfcOpeningElement(), "IfcOpeningElement") is True
|
||||
|
||||
|
||||
class TestLinkObjectData(NewFile):
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, boundary=None):
|
||||
"""Copies a space boundary
|
||||
|
||||
:param boundary: The IfcRelSpaceBoundary you want to copy.
|
||||
:type boundary: ifcopenshell.entity_instance.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
# A boring boundary with no geometry. Note that this boundary is
|
||||
# invalid and does not relate to any space or building element.
|
||||
boundary = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcRelSpaceBoundary")
|
||||
|
||||
# And now we have two
|
||||
boundary_copy = ifcopenshell.api.run("boundary.copy_boundary", model, boundary=boundary)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"boundary": boundary}
|
||||
|
||||
def execute(self):
|
||||
result = ifcopenshell.util.element.copy(self.file, self.settings["boundary"])
|
||||
if result.ConnectionGeometry:
|
||||
result.ConnectionGeometry = ifcopenshell.util.element.copy_deep(self.file, result.ConnectionGeometry)
|
||||
return result
|
||||
@@ -38,7 +38,7 @@ class Usecase:
|
||||
boundary = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcRelSpaceBoundary")
|
||||
|
||||
# Let's remove it!
|
||||
ifcopenshell.api.run("grid.remove_grid_axis", model, axis=axis_2)
|
||||
ifcopenshell.api.run("boundary.remove_boundary", model, boundary=boundary)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"boundary": boundary}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -0,0 +1,36 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
class TestCopyBoundary(test.bootstrap.IFC4):
|
||||
def test_run(self):
|
||||
boundary = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcRelSpaceBoundary")
|
||||
boundary2 = ifcopenshell.api.run("boundary.copy_boundary", self.file, boundary=boundary)
|
||||
assert boundary2.is_a("IfcRelSpaceBoundary")
|
||||
assert boundary2.GlobalId != boundary.GlobalId
|
||||
|
||||
def test_copying_connection_geometry(self):
|
||||
geometry = self.file.createIfcConnectionSurfaceGeometry()
|
||||
boundary = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcRelSpaceBoundary")
|
||||
boundary.ConnectionGeometry = geometry
|
||||
boundary2 = ifcopenshell.api.run("boundary.copy_boundary", self.file, boundary=boundary)
|
||||
assert boundary2.ConnectionGeometry.is_a("IfcConnectionSurfaceGeometry")
|
||||
assert boundary2.ConnectionGeometry != boundary.ConnectionGeometry
|
||||
Reference in New Issue
Block a user