Fix limitations in AddSlabFromWalls operator.

- The operator is now unaffected by the order in which walls are joined.
- It has been updated to support split walls.
This commit is contained in:
Bruno Perdigão
2024-12-23 17:58:08 -03:00
parent d44942fbae
commit 75483edb22
2 changed files with 43 additions and 41 deletions
+4 -7
View File
@@ -103,7 +103,7 @@ class DumbSlabGenerator:
return self.create_slab() return self.create_slab()
def derive_from_walls(self): def derive_from_walls(self):
walls, is_closed_loop = tool.Model.get_connected_walls(bpy.context.selected_objects) walls = tool.Model.get_connected_walls(bpy.context.selected_objects)
polyline_points = [] polyline_points = []
poly = tool.Model.get_polygons_from_wall_axis(walls) poly = tool.Model.get_polygons_from_wall_axis(walls)
polyline_points = [tuple([v for v in c]) for c in poly.exterior.coords] polyline_points = [tuple([v for v in c]) for c in poly.exterior.coords]
@@ -768,12 +768,9 @@ class AddSlabFromWall(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
if not self.relating_type: if not self.relating_type:
return {"FINISHED"} return {"FINISHED"}
walls, is_closed_loop = tool.Model.get_connected_walls(bpy.context.selected_objects) walls = tool.Model.get_connected_walls(bpy.context.selected_objects)
if not is_closed_loop: if not walls:
self.report( self.report({"WARNING"}, "Please select a closed loop of walls, or deselect the walls to add a slab using the polyline tool.")
{"WARNING"},
"Please select a closed loop of walls, or deselect the walls to add a slab using the polyline tool.",
)
return {"FINISHED"} return {"FINISHED"}
DumbSlabGenerator(self.relating_type).generate("WALLS") DumbSlabGenerator(self.relating_type).generate("WALLS")
+39 -34
View File
@@ -674,44 +674,39 @@ class Model(bonsai.core.tool.Model):
@classmethod @classmethod
def get_connected_walls( def get_connected_walls(
cls, walls: list[bpy.types.Object], opposite_direction: bool = False cls, walls: list[bpy.types.Object]) -> list[bpy.types.Object]:
) -> list[bpy.types.Object]:
""" """
Loop through walls by retrieving the next connected wall using the ConnectedTo attribute. Loop through walls by retrieving the next connected wall using the connection path.
If the function encounters the first wall again, it will return the list of connected walls and indicate that a closed loop has been formed. If the function encounters the first wall again, it will return the list of connected walls.
If it reaches the end of the connections, the function will call itself in the opposite direction using the ConnectedFrom method
to obtain a list of connected walls in an open loop.
""" """
is_closed_loop = False first_wall = tool.Ifc.get_entity(walls[0])
wall1 = tool.Ifc.get_entity(walls[0]) previous_wall = None
wall = wall1 current_wall = first_wall
if not opposite_direction: ordered_walls = [first_wall]
connection = "ConnectedTo"
relation = "RelatedElement"
else:
connection = "ConnectedFrom"
relation = "RelatingElement"
ordered_walls = []
ordered_walls.append(wall1)
for i in range(len(walls)): for i in range(len(walls)):
if not getattr(wall, connection) or ( paths = []
next_wall := tool.Ifc.get_object(getattr(getattr(wall, connection)[0], relation)) not in walls paths.extend([path for path in current_wall.ConnectedTo])
): paths.extend([path for path in current_wall.ConnectedFrom])
if opposite_direction:
return ordered_walls, is_closed_loop
ordered_walls, is_closed_loop = cls.get_connected_walls(walls, True)
break
next_wall = getattr(getattr(wall, connection)[0], relation)
if next_wall == wall1:
is_closed_loop = True
break
else:
ordered_walls.append(next_wall)
wall = next_wall
return [tool.Ifc.get_object(wall) for wall in ordered_walls], is_closed_loop if len(paths) <= 1:
return []
for path in paths:
next_wall = path.RelatedElement if path.RelatedElement != current_wall else path.RelatingElement
if next_wall == previous_wall:
continue
if next_wall != current_wall and next_wall != first_wall and next_wall not in ordered_walls:
ordered_walls.append(next_wall)
previous_wall = current_wall
current_wall = next_wall
break
if next_wall == first_wall:
return [tool.Ifc.get_object(wall) for wall in ordered_walls]
return []
@classmethod @classmethod
def get_polygons_from_wall_axis(cls, walls: list[bpy.types.Object]) -> list[shapely.Polygon]: def get_polygons_from_wall_axis(cls, walls: list[bpy.types.Object]) -> list[shapely.Polygon]:
@@ -727,8 +722,18 @@ class Model(bonsai.core.tool.Model):
layers2 = tool.Model.get_material_layer_parameters(tool.Ifc.get_entity(w2)) layers2 = tool.Model.get_material_layer_parameters(tool.Ifc.get_entity(w2))
axis1 = tool.Model.get_wall_axis(w1, layers1) axis1 = tool.Model.get_wall_axis(w1, layers1)
axis2 = tool.Model.get_wall_axis(w2, layers2) axis2 = tool.Model.get_wall_axis(w2, layers2)
intersection1 = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"]) intersection1 = tool.Cad.intersect_edges_v2(axis1["reference"], axis2["reference"])
intersection2 = tool.Cad.intersect_edges(axis1["side"], axis2["side"]) intersection2 = tool.Cad.intersect_edges_v2(axis1["side"], axis2["side"])
if intersection1[0] is None or intersection2[0] is None:
for v1 in axis1["reference"]:
for v2 in axis2["reference"]:
if tool.Cad.are_vectors_equal(v1, v2, 1e-5):
intersection1 = [v1]
for v1 in axis1["side"]:
for v2 in axis2["side"]:
if tool.Cad.are_vectors_equal(v1, v2, 1e-5):
intersection2 = [v1]
points1.append(intersection1[0]) points1.append(intersection1[0])
points2.append(intersection2[0]) points2.append(intersection2[0])