mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 22:11:36 +00:00
Cleaning up connections on delete_ifc
Noticed an error if you connect wall and slab, then remove the slab and try to regenerate the wall - error occured because connection to that slab wasn't removed.
The error was:
Error: Python: Traceback (most recent call last):
File "\3.6\scripts\addons\blenderbim\bim\module\model\workspace.py", line 381, in invoke
return self.execute(context)
File "\3.6\scripts\addons\blenderbim\tool\ifc.py", line 136, in execute
IfcStore.execute_ifc_operator(self, context)
File "\3.6\scripts\addons\blenderbim\bim\ifc.py", line 421, in execute_ifc_operator
result = getattr(operator, "_execute")(context)
File "\3.6\scripts\addons\blenderbim\bim\module\model\workspace.py", line 373, in _execute
getattr(self, f"hotkey_{self.hotkey}")()
File "\3.6\scripts\addons\blenderbim\bim\module\model\workspace.py", line 465, in hotkey_S_E
bpy.ops.bim.join_wall(join_type="T")
File "C:\software\Steam\steamapps\common\Blender\3.6\scripts\modules\bpy\ops.py", line 113, in __call__
ret = _op_call(self.idname_py(), None, kw)
RuntimeError: Error: Python: Traceback (most recent call last):
File "\3.6\scripts\addons\blenderbim\tool\ifc.py", line 136, in execute
IfcStore.execute_ifc_operator(self, context)
File "\3.6\scripts\addons\blenderbim\bim\ifc.py", line 421, in execute_ifc_operator
result = getattr(operator, "_execute")(context)
File "\3.6\scripts\addons\blenderbim\bim\module\model\wall.py", line 76, in _execute
joiner.join_E(context.active_object, context.scene.cursor.location)
File "\3.6\scripts\addons\blenderbim\bim\module\model\wall.py", line 1038, in join_E
self.recreate_wall(element1, wall1, axis, body)
File "\3.6\scripts\addons\blenderbim\bim\module\model\wall.py", line 1145, in recreate_wall
height = self.clip(obj, tool.Ifc.get_object(rel.RelatingElement))
File "\3.6\scripts\addons\blenderbim\tool\ifc.py", line 89, in get_object
return IfcStore.get_element(element.id())
AttributeError: 'NoneType' object has no attribute 'id'
This commit is contained in:
@@ -60,11 +60,11 @@ class JoinWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
for obj in selected_objs:
|
for obj in selected_objs:
|
||||||
joiner.unjoin(obj)
|
joiner.unjoin(obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if not context.active_object or not context.active_object.BIMObjectProperties.ifc_definition_id:
|
if not context.active_object or not context.active_object.BIMObjectProperties.ifc_definition_id:
|
||||||
self.report({"ERROR"}, f"No active object selected")
|
self.report({"ERROR"}, f"No active object selected")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
for obj in selected_objs:
|
for obj in selected_objs:
|
||||||
tool.Geometry.clear_scale(obj)
|
tool.Geometry.clear_scale(obj)
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ class JoinWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if len(selected_objs) == 1:
|
if len(selected_objs) == 1:
|
||||||
joiner.join_E(context.active_object, context.scene.cursor.location)
|
joiner.join_E(context.active_object, context.scene.cursor.location)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if self.join_type in ("L", "V"):
|
if self.join_type in ("L", "V"):
|
||||||
if len(selected_objs) != 2:
|
if len(selected_objs) != 2:
|
||||||
self.report({"ERROR"}, f"It requires 2 selected objects to do join of type {self.join_type}")
|
self.report({"ERROR"}, f"It requires 2 selected objects to do join of type {self.join_type}")
|
||||||
@@ -86,7 +86,7 @@ class JoinWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
elif self.join_type == "V":
|
elif self.join_type == "V":
|
||||||
joiner.join_V(another_selected_object, context.active_object)
|
joiner.join_V(another_selected_object, context.active_object)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if self.join_type == "T":
|
if self.join_type == "T":
|
||||||
elements = [tool.Ifc.get_entity(o) for o in context.selected_objects]
|
elements = [tool.Ifc.get_entity(o) for o in context.selected_objects]
|
||||||
layer2_elements = []
|
layer2_elements = []
|
||||||
@@ -560,7 +560,7 @@ class DumbWallGenerator:
|
|||||||
|
|
||||||
rotation = math.atan2(normal[1], normal[0])
|
rotation = math.atan2(normal[1], normal[0])
|
||||||
rotated_y_axis = Matrix.Rotation(-rotation, 4, "Z")[1].xyz
|
rotated_y_axis = Matrix.Rotation(-rotation, 4, "Z")[1].xyz
|
||||||
|
|
||||||
# since wall thickness goes by local Y+ axis
|
# since wall thickness goes by local Y+ axis
|
||||||
# we find best position for the next wall
|
# we find best position for the next wall
|
||||||
# by finding the face of another wall that will be very close to the some test point.
|
# by finding the face of another wall that will be very close to the some test point.
|
||||||
@@ -1137,7 +1137,7 @@ class DumbWallJoiner:
|
|||||||
|
|
||||||
previous_matrix = obj.matrix_world.copy()
|
previous_matrix = obj.matrix_world.copy()
|
||||||
previous_origin = previous_matrix.col[3].to_2d()
|
previous_origin = previous_matrix.col[3].to_2d()
|
||||||
obj.matrix_world[0][3], obj.matrix_world[1][3] = self.body[0]
|
obj.matrix_world.col[3].xy = self.body[0]
|
||||||
bpy.context.view_layer.update()
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
for rel in element.ConnectedFrom:
|
for rel in element.ConnectedFrom:
|
||||||
@@ -1432,6 +1432,7 @@ class DumbWallJoiner:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def clip(self, wall1, slab2):
|
def clip(self, wall1, slab2):
|
||||||
|
"""returns height of the clipped wall, adds clipping plane to `clippings`"""
|
||||||
element1 = tool.Ifc.get_entity(wall1)
|
element1 = tool.Ifc.get_entity(wall1)
|
||||||
element2 = tool.Ifc.get_entity(slab2)
|
element2 = tool.Ifc.get_entity(slab2)
|
||||||
|
|
||||||
@@ -1441,19 +1442,15 @@ class DumbWallJoiner:
|
|||||||
bases = [axis1["base"][0].to_3d(), axis1["base"][1].to_3d(), axis1["side"][0].to_3d(), axis1["side"][1].to_3d()]
|
bases = [axis1["base"][0].to_3d(), axis1["base"][1].to_3d(), axis1["side"][0].to_3d(), axis1["side"][1].to_3d()]
|
||||||
|
|
||||||
extrusion = self.get_extrusion_data(tool.Ifc.get().by_id(wall1.data.BIMMeshProperties.ifc_definition_id))
|
extrusion = self.get_extrusion_data(tool.Ifc.get().by_id(wall1.data.BIMMeshProperties.ifc_definition_id))
|
||||||
d = wall1.matrix_world.to_quaternion() @ extrusion["direction"]
|
wall_dir = wall1.matrix_world.to_quaternion() @ extrusion["direction"]
|
||||||
|
|
||||||
slab_pt = slab2.matrix_world @ Vector((0, 0, 0))
|
slab_pt = slab2.matrix_world @ Vector((0, 0, 0))
|
||||||
slab_dir = slab2.matrix_world.to_quaternion() @ Vector((0, 0, -1))
|
slab_dir = slab2.matrix_world.to_quaternion() @ Vector((0, 0, -1))
|
||||||
|
|
||||||
tops = [mathutils.geometry.intersect_line_plane(b, b + d, slab_pt, slab_dir) for b in bases]
|
tops = [mathutils.geometry.intersect_line_plane(b, b + wall_dir, slab_pt, slab_dir) for b in bases]
|
||||||
|
top_index = max(range(4), key=lambda i: tops[i].z)
|
||||||
i_bottom = None
|
i_top = tops[top_index]
|
||||||
i_top = None
|
i_bottom = bases[top_index]
|
||||||
for i, co in enumerate(tops):
|
|
||||||
if i_top is None or co[2] > i_top[2]:
|
|
||||||
i_top = co
|
|
||||||
i_bottom = bases[i]
|
|
||||||
|
|
||||||
quaternion = slab2.matrix_world.to_quaternion()
|
quaternion = slab2.matrix_world.to_quaternion()
|
||||||
x_axis = quaternion @ Vector((1, 0, 0))
|
x_axis = quaternion @ Vector((1, 0, 0))
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
if len(bpy.context.selected_objects) == 1:
|
if len(bpy.context.selected_objects) == 1:
|
||||||
if self.active_material_usage == "LAYER3":
|
if self.active_material_usage == "LAYER3":
|
||||||
# Edit LAYER2 profile
|
# Edit LAYER3 profile
|
||||||
if bpy.context.active_object and bpy.context.active_object.mode == "OBJECT":
|
if bpy.context.active_object and bpy.context.active_object.mode == "OBJECT":
|
||||||
bpy.ops.bim.enable_editing_extrusion_profile()
|
bpy.ops.bim.enable_editing_extrusion_profile()
|
||||||
elif self.active_material_usage == "LAYER2":
|
elif self.active_material_usage == "LAYER2":
|
||||||
@@ -469,6 +469,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
else:
|
else:
|
||||||
# Edit SWEPTSOLID profile (assuming single profile for now)
|
# Edit SWEPTSOLID profile (assuming single profile for now)
|
||||||
bpy.ops.bim.enable_editing_extrusion_profile()
|
bpy.ops.bim.enable_editing_extrusion_profile()
|
||||||
|
|
||||||
elif self.active_material_usage == "LAYER2" and selected_usages.get("PROFILE", []):
|
elif self.active_material_usage == "LAYER2" and selected_usages.get("PROFILE", []):
|
||||||
# Extend PROFILEs to LAYER2
|
# Extend PROFILEs to LAYER2
|
||||||
[o.select_set(False) for o in selected_usages.get("LAYER3", [])]
|
[o.select_set(False) for o in selected_usages.get("LAYER3", [])]
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
if element.is_a("IfcRelSpaceBoundary"):
|
if element.is_a("IfcRelSpaceBoundary"):
|
||||||
ifcopenshell.api.run("boundary.remove_boundary", tool.Ifc.get(), boundary=element)
|
ifcopenshell.api.run("boundary.remove_boundary", tool.Ifc.get(), boundary=element)
|
||||||
return bpy.data.objects.remove(obj)
|
return bpy.data.objects.remove(obj)
|
||||||
|
|
||||||
|
if element.is_a("IfcElement"):
|
||||||
|
connections = element.ConnectedTo + element.ConnectedFrom
|
||||||
|
for connection in connections:
|
||||||
|
tool.Ifc.get().remove(connection)
|
||||||
|
|
||||||
collection = obj.BIMObjectProperties.collection
|
collection = obj.BIMObjectProperties.collection
|
||||||
if collection:
|
if collection:
|
||||||
parent = ifcopenshell.util.element.get_aggregate(element)
|
parent = ifcopenshell.util.element.get_aggregate(element)
|
||||||
|
|||||||
Reference in New Issue
Block a user