mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
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:
@@ -364,7 +364,8 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
# TODO: write unit tests to see how this bulk operation handles
|
# TODO: write unit tests to see how this bulk operation handles
|
||||||
# contradictory ifc_representation_class values and when
|
# contradictory ifc_representation_class values and when
|
||||||
# ifc_representation_class is IfcTextLiteral
|
# ifc_representation_class is IfcTextLiteral
|
||||||
if not obj.data:
|
data = obj.data
|
||||||
|
if not tool.Geometry.is_data_supported_for_adding_representation(data):
|
||||||
continue
|
continue
|
||||||
self.update_obj_mesh_representation(context, obj)
|
self.update_obj_mesh_representation(context, obj)
|
||||||
tool.Ifc.finish_edit(obj)
|
tool.Ifc.finish_edit(obj)
|
||||||
|
|||||||
@@ -172,7 +172,13 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMRootProperties
|
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:
|
if not objects:
|
||||||
self.report({"INFO"}, "No objects selected.")
|
self.report({"INFO"}, "No objects selected.")
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING, Optional, Sequence
|
from typing import TYPE_CHECKING, Optional, Sequence, Union
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import bpy
|
import bpy
|
||||||
@@ -47,7 +47,8 @@ def add_representation(
|
|||||||
context: ifcopenshell.entity_instance,
|
context: ifcopenshell.entity_instance,
|
||||||
ifc_representation_class: Optional[str] = None,
|
ifc_representation_class: Optional[str] = None,
|
||||||
profile_set_usage: Optional[ifcopenshell.entity_instance] = 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)
|
element = ifc.get_entity(obj)
|
||||||
if not element:
|
if not element:
|
||||||
return
|
return
|
||||||
@@ -55,7 +56,7 @@ def add_representation(
|
|||||||
edit_object_placement(ifc, geometry, surveyor, obj=obj)
|
edit_object_placement(ifc, geometry, surveyor, obj=obj)
|
||||||
data = geometry.get_object_data(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
|
return
|
||||||
|
|
||||||
representation = ifc.run(
|
representation = ifc.run(
|
||||||
|
|||||||
@@ -407,6 +407,7 @@ class Geometry:
|
|||||||
def import_representation_parameters(cls, data): pass
|
def import_representation_parameters(cls, data): pass
|
||||||
def is_body_representation(cls, representation): pass
|
def is_body_representation(cls, representation): pass
|
||||||
def is_box_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_edited(cls, obj): pass
|
||||||
def is_mapped_representation(cls, representation): pass
|
def is_mapped_representation(cls, representation): pass
|
||||||
def is_type_product(cls, element): pass
|
def is_type_product(cls, element): pass
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ from collections import defaultdict
|
|||||||
from math import radians, pi
|
from math import radians, pi
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from bonsai.bim.ifc import IfcStore
|
from bonsai.bim.ifc import IfcStore
|
||||||
from typing import Union, Iterable, Optional, Literal
|
from typing import Union, Iterable, Optional, Literal, Iterator
|
||||||
from typing import Iterator
|
from typing_extensions import TypeIs
|
||||||
|
|
||||||
|
|
||||||
class Geometry(bonsai.core.tool.Geometry):
|
class Geometry(bonsai.core.tool.Geometry):
|
||||||
@@ -477,7 +477,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
return hasher.hexdigest()
|
return hasher.hexdigest()
|
||||||
|
|
||||||
@classmethod
|
@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
|
return obj.data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -646,6 +646,21 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
def is_box_representation(cls, representation: ifcopenshell.entity_instance) -> bool:
|
def is_box_representation(cls, representation: ifcopenshell.entity_instance) -> bool:
|
||||||
return representation.ContextOfItems.ContextIdentifier == "Box"
|
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
|
@classmethod
|
||||||
def is_edited(cls, obj: bpy.types.Object) -> bool:
|
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
|
return not all([tool.Cad.is_x(o, 1.0) for o in obj.scale]) or obj in IfcStore.edited_objs
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class TestAddRepresentation:
|
|||||||
|
|
||||||
# Add representation
|
# Add representation
|
||||||
geometry.get_object_data("obj").should_be_called().will_return("data")
|
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_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.get_total_representation_items("obj").should_be_called().will_return(1)
|
||||||
geometry.should_force_faceted_brep().should_be_called().will_return(False)
|
geometry.should_force_faceted_brep().should_be_called().will_return(False)
|
||||||
@@ -108,6 +109,7 @@ class TestAddRepresentation:
|
|||||||
|
|
||||||
# Add representation
|
# Add representation
|
||||||
geometry.get_object_data("obj").should_be_called().will_return("data")
|
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_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.get_total_representation_items("obj").should_be_called().will_return(1)
|
||||||
geometry.should_force_faceted_brep().should_be_called().will_return(False)
|
geometry.should_force_faceted_brep().should_be_called().will_return(False)
|
||||||
@@ -158,7 +160,8 @@ class TestAddRepresentation:
|
|||||||
TestEditObjectPlacement.predict(self, ifc, geometry, surveyor)
|
TestEditObjectPlacement.predict(self, ifc, geometry, surveyor)
|
||||||
|
|
||||||
# Add representation
|
# 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 (
|
assert (
|
||||||
subject.add_representation(
|
subject.add_representation(
|
||||||
ifc,
|
ifc,
|
||||||
|
|||||||
Reference in New Issue
Block a user