mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Bonsai: guard import_item against a None geometry shape
Editing an IfcRepresentationItem and exiting item edit mode re-imports its geometry through tool.Geometry.import_item, which calls tool.Loader.create_generic_shape(item) and immediately passes the result to ifcopenshell.util.shape.get_vertices without checking it. The geometry kernel can legitimately return None for an item, for example when a boolean or clipping result is invalid or has no remaining volume, which is exactly what every other caller of create_generic_shape already guards against (import_ifc.py and tool/loader.py both check the result before using it). Without the same guard here, get_vertices(None) raises an unhandled AttributeError partway through import_item, after obj.data.clear_geometry() has already run, leaving the item's mesh cleared and the operator aborted instead of failing gracefully. This adds the same None check used elsewhere in the codebase: on failure we log a clear error naming the offending item instead of crashing, and skip only the geometry-dependent steps. Fixes #6693. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -2230,16 +2230,33 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
obj.data.from_pydata([co], [], [])
|
||||
else:
|
||||
geometry = tool.Loader.create_generic_shape(item)
|
||||
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
||||
if (cartesian_point_offset := cls.get_cartesian_point_offset(rep_obj)) is not None:
|
||||
verts = verts - cartesian_point_offset
|
||||
tool.Loader.convert_geometry_to_mesh(geometry, obj.data, verts=verts)
|
||||
if geometry is None:
|
||||
# The geometry kernel can legitimately fail to produce a shape for an
|
||||
# item (e.g. an invalid or degenerate boolean/clipping result). Every
|
||||
# other caller of create_generic_shape already guards against this
|
||||
# (see import_ifc.py and tool/loader.py). Without the same guard here,
|
||||
# get_vertices(None) raises an unhandled AttributeError which aborts
|
||||
# mid-edit after obj.data.clear_geometry() already ran, leaving the
|
||||
# item's mesh empty/corrupted instead of failing gracefully.
|
||||
logging.getLogger("ImportIFC").error(
|
||||
"Failed to regenerate geometry for representation item #%d (%s). "
|
||||
"Its mesh has been cleared - check for invalid geometry, such as "
|
||||
"a boolean or clipping result with no remaining volume.",
|
||||
item.id(),
|
||||
item.is_a(),
|
||||
)
|
||||
obj.matrix_world = rep_obj.matrix_world.copy()
|
||||
else:
|
||||
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
||||
if (cartesian_point_offset := cls.get_cartesian_point_offset(rep_obj)) is not None:
|
||||
verts = verts - cartesian_point_offset
|
||||
tool.Loader.convert_geometry_to_mesh(geometry, obj.data, verts=verts)
|
||||
|
||||
if ios_materials := list(obj.data["ios_materials"]):
|
||||
material = tool.Ifc.get_object(tool.Ifc.get().by_id(ios_materials[0]))
|
||||
obj.data.materials.append(material)
|
||||
if ios_materials := list(obj.data["ios_materials"]):
|
||||
material = tool.Ifc.get_object(tool.Ifc.get().by_id(ios_materials[0]))
|
||||
obj.data.materials.append(material)
|
||||
|
||||
obj.matrix_world = rep_obj.matrix_world.copy()
|
||||
obj.matrix_world = rep_obj.matrix_world.copy()
|
||||
|
||||
if is_swept_area := item.is_a("IfcSweptAreaSolid"):
|
||||
position = item.Position
|
||||
|
||||
Reference in New Issue
Block a user