Fix Image empty interpreted as Mesh #5194

Apparently we can't trust `obj.data == None` to identify empties since in Blender there are empties that can use `bpy.types.Image` as their `obj.data`.
This commit is contained in:
Andrej730
2024-08-21 14:47:07 +05:00
parent 45fed747c2
commit ef04402ed8
6 changed files with 36 additions and 9 deletions
@@ -364,7 +364,8 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
# TODO: write unit tests to see how this bulk operation handles
# contradictory ifc_representation_class values and when
# ifc_representation_class is IfcTextLiteral
if not obj.data:
data = obj.data
if not tool.Geometry.is_data_supported_for_adding_representation(data):
continue
self.update_obj_mesh_representation(context, obj)
tool.Ifc.finish_edit(obj)
@@ -172,7 +172,13 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
props = context.scene.BIMRootProperties
objects = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects or [context.active_object]
objects: list[bpy.types.Object] = []
if self.obj:
objects = [bpy.data.objects[self.obj]]
elif objects := context.selected_objects:
pass
elif obj := context.active_object:
objects = [obj]
if not objects:
self.report({"INFO"}, "No objects selected.")
+4 -3
View File
@@ -17,7 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Sequence
from typing import TYPE_CHECKING, Optional, Sequence, Union
if TYPE_CHECKING:
import bpy
@@ -47,7 +47,8 @@ def add_representation(
context: ifcopenshell.entity_instance,
ifc_representation_class: Optional[str] = None,
profile_set_usage: Optional[ifcopenshell.entity_instance] = None,
) -> ifcopenshell.entity_instance:
) -> Union[ifcopenshell.entity_instance, None]:
"""Add IFC representation based on object `.data`."""
element = ifc.get_entity(obj)
if not element:
return
@@ -55,7 +56,7 @@ def add_representation(
edit_object_placement(ifc, geometry, surveyor, obj=obj)
data = geometry.get_object_data(obj)
if not data and ifc_representation_class != "IfcTextLiteral":
if not geometry.is_data_supported_for_adding_representation(data) and ifc_representation_class != "IfcTextLiteral":
return
representation = ifc.run(
+1
View File
@@ -407,6 +407,7 @@ class Geometry:
def import_representation_parameters(cls, data): pass
def is_body_representation(cls, representation): pass
def is_box_representation(cls, representation): pass
def is_data_supported_for_adding_representation(cls, data): pass
def is_edited(cls, obj): pass
def is_mapped_representation(cls, representation): pass
def is_type_product(cls, element): pass
+18 -3
View File
@@ -41,8 +41,8 @@ from collections import defaultdict
from math import radians, pi
from mathutils import Vector, Matrix
from bonsai.bim.ifc import IfcStore
from typing import Union, Iterable, Optional, Literal
from typing import Iterator
from typing import Union, Iterable, Optional, Literal, Iterator
from typing_extensions import TypeIs
class Geometry(bonsai.core.tool.Geometry):
@@ -477,7 +477,7 @@ class Geometry(bonsai.core.tool.Geometry):
return hasher.hexdigest()
@classmethod
def get_object_data(cls, obj: bpy.types.Object) -> bpy.types.ID:
def get_object_data(cls, obj: bpy.types.Object) -> Union[bpy.types.ID, None]:
return obj.data
@classmethod
@@ -646,6 +646,21 @@ class Geometry(bonsai.core.tool.Geometry):
def is_box_representation(cls, representation: ifcopenshell.entity_instance) -> bool:
return representation.ContextOfItems.ContextIdentifier == "Box"
@classmethod
def is_data_supported_for_adding_representation(cls, data: Union[bpy.types.ID, None]) -> TypeIs[
Union[
bpy.types.Mesh,
bpy.types.Curve,
]
]:
supported_types = (
bpy.types.Mesh,
bpy.types.Curve,
)
if not data:
return False
return isinstance(data, supported_types)
@classmethod
def is_edited(cls, obj: bpy.types.Object) -> bool:
return not all([tool.Cad.is_x(o, 1.0) for o in obj.scale]) or obj in IfcStore.edited_objs
+4 -1
View File
@@ -42,6 +42,7 @@ class TestAddRepresentation:
# Add representation
geometry.get_object_data("obj").should_be_called().will_return("data")
geometry.is_data_supported_for_adding_representation("data").should_be_called().will_return(True)
geometry.get_cartesian_point_coordinate_offset("obj").should_be_called().will_return("coordinate_offset")
geometry.get_total_representation_items("obj").should_be_called().will_return(1)
geometry.should_force_faceted_brep().should_be_called().will_return(False)
@@ -108,6 +109,7 @@ class TestAddRepresentation:
# Add representation
geometry.get_object_data("obj").should_be_called().will_return("data")
geometry.is_data_supported_for_adding_representation("data").should_be_called().will_return(True)
geometry.get_cartesian_point_coordinate_offset("obj").should_be_called().will_return("coordinate_offset")
geometry.get_total_representation_items("obj").should_be_called().will_return(1)
geometry.should_force_faceted_brep().should_be_called().will_return(False)
@@ -158,7 +160,8 @@ class TestAddRepresentation:
TestEditObjectPlacement.predict(self, ifc, geometry, surveyor)
# Add representation
geometry.get_object_data("obj").should_be_called().will_return(None)
geometry.get_object_data("obj").should_be_called().will_return("data")
geometry.is_data_supported_for_adding_representation("data").should_be_called().will_return(False)
assert (
subject.add_representation(
ifc,