From e78127d54f1a340aa939897256684989bed7db1e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 9 Mar 2025 18:00:13 +1100 Subject: [PATCH] See #1227. Don't move any child at all when regenerating wall body. --- src/bonsai/bonsai/bim/module/model/wall.py | 50 +------------------ src/bonsai/bonsai/core/model.py | 2 +- .../api/geometry/edit_object_placement.py | 2 +- .../regenerate_wall_representation.py | 14 +++++- 4 files changed, 16 insertions(+), 52 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index c712d6f9ad..f5d69c0415 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -1106,7 +1106,7 @@ class DumbWallJoiner: else: ifcopenshell.api.geometry.assign_representation(self.file, product=wall, representation=rep) - def join_E(self, wall1, target): + def extend(self, wall1, target): if tool.Ifc.is_moved(wall1): bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=wall1) element1 = tool.Ifc.get_entity(wall1) @@ -1192,54 +1192,6 @@ class DumbWallJoiner: matrix[:, 3] *= unit_scale obj.matrix_world = tool.Loader.apply_blender_offset_to_matrix_world(obj, matrix) tool.Geometry.record_object_position(obj) - return - - wall_moved = tool.Ifc.is_moved(obj) - if wall_moved: - # Openings should move with the host overall ... - # ... except their position should stay the same along the local X axis of the wall - for opening in [ - r.RelatedOpeningElement for r in element.HasOpenings if not r.RelatedOpeningElement.HasFillings - ]: - percent = tool.Cad.edge_percent( - self.body[0], (previous_origin, (previous_matrix @ Vector((1, 0, 0))).to_2d()) - ) - is_x_offset_increased = True if percent < 0 else False - - change_in_x = (self.body[0] - previous_origin).length / self.unit_scale - coordinates = list(opening.ObjectPlacement.RelativePlacement.Location.Coordinates) - if is_x_offset_increased: - coordinates[0] += change_in_x - else: - coordinates[0] -= change_in_x - opening.ObjectPlacement.RelativePlacement.Location.Coordinates = coordinates - - bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) - - # If opening has filling then stick to the filling's position - # We're applying new openings position only after wall position is applied - for opening in [r.RelatedOpeningElement for r in element.HasOpenings if r.RelatedOpeningElement.HasFillings]: - similar_openings = bonsai.core.geometry.get_similar_openings(tool.Ifc, opening) - filling_obj = tool.Ifc.get_object(opening.HasFillings[0].RelatedBuildingElement) - filling_moved = tool.Ifc.is_moved(filling_obj) - if filling_moved: - bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=filling_obj) - if filling_moved or wall_moved: - ifcopenshell.api.run( - "geometry.edit_object_placement", tool.Ifc.get(), product=opening, matrix=filling_obj.matrix_world - ) - bonsai.core.geometry.edit_similar_opening_placement(tool.Geometry, opening, similar_openings) - - bonsai.core.geometry.switch_representation( - tool.Ifc, - tool.Geometry, - obj=obj, - representation=new_body, - should_reload=True, - is_global=True, - should_sync_changes_first=False, - ) - tool.Geometry.record_object_materials(obj) def create_matrix(self, p, x, y, z): return Matrix([x, y, z, p]).to_4x4().transposed() diff --git a/src/bonsai/bonsai/core/model.py b/src/bonsai/bonsai/core/model.py index fe9851e1f9..d04486ed1c 100644 --- a/src/bonsai/bonsai/core/model.py +++ b/src/bonsai/bonsai/core/model.py @@ -35,7 +35,7 @@ def extend_walls( if not (element := ifc.get_entity(obj)) or model.get_usage_type(element) != "LAYER2": continue geometry.clear_scale(obj) - joiner.join_E(obj, target) + joiner.extend(obj, target) def join_walls_LV( diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py index 11d53364b3..78e95c32c8 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py @@ -155,7 +155,7 @@ class Usecase: elif obj.is_a("IfcFeatureElement"): # Feature elements affect the geometry of their parent, and # so logically should always move with the parent. However, - # subchildren shouldn't move. + # subchildren (fillings) shouldn't move. placement2 = obj.ObjectPlacement for referenced_placement2 in placement2.ReferencedByPlacements: matrix2 = ifcopenshell.util.placement.get_local_placement(referenced_placement2) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/regenerate_wall_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/regenerate_wall_representation.py index 4702912b0e..5f72756c56 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/regenerate_wall_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/regenerate_wall_representation.py @@ -311,12 +311,24 @@ class Regenerator: ifcopenshell.api.geometry.assign_representation(self.file, product=wall, representation=axis_rep) if not np.allclose(self.reference_p1, np.array((0.0, 0.0))): + children = [] + for referenced_placement in wall.ObjectPlacement.ReferencedByPlacements: + matrix = ifcopenshell.util.placement.get_local_placement(referenced_placement) + children.append((matrix, referenced_placement.PlacesObject)) + matrix = ifcopenshell.util.placement.get_local_placement(wall.ObjectPlacement) matrix[:, 3] = matrix @ np.concatenate((self.reference_p1, (0, 1))) ifcopenshell.api.geometry.edit_object_placement( - self.file, product=wall, matrix=matrix, is_si=False, should_transform_children=False + self.file, product=wall, matrix=matrix, is_si=False, should_transform_children=True ) + # Restore children to their previous location + for matrix, elements in children: + for element in elements: + ifcopenshell.api.geometry.edit_object_placement( + self.file, product=element, matrix=matrix, is_si=False, should_transform_children=True + ) + return body_rep def join(self, wall1, wall2, layers1, layers2, connection1, connection2):