diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 0e7017edd1..d8a2f8a006 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -90,20 +90,22 @@ class OverrideMeshSeparate(bpy.types.Operator, tool.Ifc.Operator): self.report({"INFO"}, f"Separating an {item.is_a()} is not supported") def add_meshlike_item(self, obj: bpy.types.Object) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() obj.show_in_front = True tool.Geometry.lock_object(obj) builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + rep_obj = props.representation_obj + assert rep_obj if (coordinate_offset := tool.Geometry.get_cartesian_point_offset(rep_obj)) is not None: verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] else: verts = [v.co / unit_scale for v in obj.data.vertices] faces = [p.vertices[:] for p in obj.data.polygons] - representation = tool.Geometry.get_active_representation(props.representation_obj) + representation = tool.Geometry.get_active_representation(rep_obj) + assert representation representation = ifcopenshell.util.representation.resolve_representation(representation) if representation.RepresentationType in ("Brep", "AdvancedBrep"): @@ -212,8 +214,8 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): obj = context.active_object assert obj - props = context.scene.BIMGeometryProperties - oprops = obj.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() + oprops = tool.Geometry.get_object_geometry_props(obj) ifc_context = int(oprops.contexts or "0") or None if not ifc_context: return @@ -1661,7 +1663,7 @@ class OverrideJoin(bpy.types.Operator, tool.Ifc.Operator): return self.join_blender_obj() def join_item(self) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() ifc_file = tool.Ifc.get() item = tool.Ifc.get().by_id(self.target.data.BIMMeshProperties.ifc_definition_id) if tool.Geometry.is_meshlike_item(item): @@ -1941,7 +1943,8 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator): def handle_single_object(self, context: bpy.types.Context, obj: bpy.types.Object) -> None: element = tool.Ifc.get_entity(obj) - if obj == context.scene.BIMGeometryProperties.representation_obj: + props = tool.Geometry.get_geometry_props() + if obj == props.representation_obj: self.report({"ERROR"}, f"Element '{obj.name}' is in item mode and cannot be edited directly") elif obj in [o.obj for o in context.scene.BIMAggregateProperties.not_editing_objects]: obj.select_set(False) @@ -2298,7 +2301,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator): obj.data.BIMMeshProperties.ifc_definition_id = new.id() tool.Geometry.import_item(obj) - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() for item in additional_curves: representation = tool.Geometry.get_active_representation(props.representation_obj) representation = ifcopenshell.util.representation.resolve_representation(representation) @@ -2452,7 +2455,8 @@ class SelectRepresentationItem(bpy.types.Operator): @classmethod def poll(cls, context): - if not context.scene.BIMGeometryProperties.representation_obj: + props = tool.Geometry.get_geometry_props() + if not props.representation_obj: cls.poll_message_set("No object opened in item mode.") return False return True @@ -2462,7 +2466,7 @@ class SelectRepresentationItem(bpy.types.Operator): item = tool.Ifc.get().by_id(obj.BIMGeometryProperties.active_item.ifc_definition_id) item_ids = self.get_nested_item_ids(item) - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() for item_obj in props.item_objs: if item_obj.obj.data.BIMMeshProperties.ifc_definition_id in item_ids: tool.Blender.select_object(item_obj.obj) @@ -2889,7 +2893,7 @@ class AddMeshlikeItem(bpy.types.Operator, tool.Ifc.Operator): shape: bpy.props.StringProperty(name="Shape") def _execute(self, context): - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() mesh = bpy.data.meshes.new("Tmp") obj = bpy.data.objects.new("Tmp", mesh) scene = bpy.context.scene @@ -2923,7 +2927,7 @@ class AddMeshlikeItem(bpy.types.Operator, tool.Ifc.Operator): builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + rep_obj = tool.Geometry.get_geometry_props().representation_obj if (coordinate_offset := tool.Geometry.get_cartesian_point_offset(rep_obj)) is not None: verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] else: @@ -2953,7 +2957,7 @@ class AddSweptAreaSolidItem(bpy.types.Operator, tool.Ifc.Operator): shape: bpy.props.StringProperty(name="Shape") def _execute(self, context): - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() mesh = bpy.data.meshes.new("Tmp") obj = bpy.data.objects.new("Tmp", mesh) scene = bpy.context.scene @@ -3009,7 +3013,7 @@ class AddCurvelikeItem(bpy.types.Operator, tool.Ifc.Operator): shape: CurveShape def _execute(self, context): - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() representation = tool.Geometry.get_active_representation(props.representation_obj) is_2d = representation.ContextOfItems.ContextType == "Plan" @@ -3082,7 +3086,7 @@ class AddHalfSpaceSolidItem(bpy.types.Operator, tool.Ifc.Operator): self.report({"ERROR"}, "Select an item to apply the half space solid to.") return {"CANCELLED"} - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() mesh = bpy.data.meshes.new("Tmp") obj = bpy.data.objects.new("Tmp", mesh) scene = bpy.context.scene diff --git a/src/bonsai/bonsai/bim/module/geometry/ui.py b/src/bonsai/bonsai/bim/module/geometry/ui.py index 13463b52e2..01d0a8ae0e 100644 --- a/src/bonsai/bonsai/bim/module/geometry/ui.py +++ b/src/bonsai/bonsai/bim/module/geometry/ui.py @@ -224,7 +224,9 @@ class BIM_PT_representation_items(Panel): if not RepresentationItemsData.is_loaded: RepresentationItemsData.load() - obj = context.scene.BIMGeometryProperties.representation_obj or tool.Blender.get_active_object() + props = tool.Geometry.get_geometry_props() + obj = props.representation_obj or tool.Blender.get_active_object() + assert obj props = tool.Geometry.get_object_geometry_props(obj) row = self.layout.row(align=True) @@ -576,7 +578,7 @@ class BIM_PT_workarounds(Panel): ) def draw(self, context): - props = context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() row = self.layout.row() row.prop(props, "should_force_faceted_brep") row = self.layout.row() diff --git a/src/bonsai/bonsai/bim/module/model/data.py b/src/bonsai/bonsai/bim/module/model/data.py index 813aea1d8a..cc713e5bd7 100644 --- a/src/bonsai/bonsai/bim/module/model/data.py +++ b/src/bonsai/bonsai/bim/module/model/data.py @@ -662,19 +662,19 @@ class ItemData: @classmethod def representation_identifier(cls): - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() rep = tool.Geometry.get_active_representation(props.representation_obj) return rep.RepresentationIdentifier @classmethod def representation_type(cls): - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() rep = tool.Geometry.get_active_representation(props.representation_obj) return rep.RepresentationType @classmethod def representation_usage(cls): - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() return tool.Model.get_usage_type(tool.Ifc.get_entity(props.representation_obj)) @classmethod diff --git a/src/bonsai/bonsai/bim/module/model/opening.py b/src/bonsai/bonsai/bim/module/model/opening.py index 6d63050fc5..0e73e71a91 100644 --- a/src/bonsai/bonsai/bim/module/model/opening.py +++ b/src/bonsai/bonsai/bim/module/model/opening.py @@ -471,7 +471,7 @@ class AddBoolean(Operator, tool.Ifc.Operator): second_items = [tool.Ifc.get().by_id(o.data.BIMMeshProperties.ifc_definition_id) for o in second_objs] booleans = ifcopenshell.api.geometry.add_boolean(tool.Ifc.get(), first_item, second_items, props.operator) - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + rep_obj = tool.Geometry.get_geometry_props().representation_obj rep_element = tool.Ifc.get_entity(rep_obj) tool.Model.mark_manual_booleans(rep_element, booleans) tool.Geometry.reload_representation(rep_obj) @@ -826,7 +826,8 @@ class RemoveBoolean(Operator, tool.Ifc.Operator): tool.Ifc.get(), tool.Ifc.get().by_id(props.active_boolean.ifc_definition_id) ) bpy.ops.bim.enable_editing_booleans() - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + rep_obj = tool.Geometry.get_geometry_props().representation_obj + assert rep_obj tool.Geometry.reload_representation(rep_obj) tool.Root.reload_item_decorator() diff --git a/src/bonsai/bonsai/bim/module/void/data.py b/src/bonsai/bonsai/bim/module/void/data.py index f3d60ec439..fe387b6f81 100644 --- a/src/bonsai/bonsai/bim/module/void/data.py +++ b/src/bonsai/bonsai/bim/module/void/data.py @@ -125,7 +125,8 @@ class BooleansData: @classmethod def booleans(cls): - obj = bpy.context.scene.BIMGeometryProperties.representation_obj or bpy.context.active_object + props = tool.Geometry.get_geometry_props() + obj = props.representation_obj or bpy.context.active_object if ( not obj.data or not hasattr(obj.data, "BIMMeshProperties") @@ -138,7 +139,8 @@ class BooleansData: @classmethod def manual_booleans(cls): - obj = bpy.context.scene.BIMGeometryProperties.representation_obj or bpy.context.active_object + props = tool.Geometry.get_geometry_props() + obj = props.representation_obj or bpy.context.active_object if ( not obj.data or not hasattr(obj.data, "BIMMeshProperties") diff --git a/src/bonsai/bonsai/bim/module/void/operator.py b/src/bonsai/bonsai/bim/module/void/operator.py index 067dc91332..5867ed9950 100644 --- a/src/bonsai/bonsai/bim/module/void/operator.py +++ b/src/bonsai/bonsai/bim/module/void/operator.py @@ -311,8 +311,11 @@ class EnableEditingBooleans(bpy.types.Operator): def execute(self, context): props = context.scene.BIMBooleanProperties - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + gprops = tool.Geometry.get_geometry_props() + rep_obj = gprops.representation_obj + assert rep_obj representation = tool.Geometry.get_active_representation(rep_obj) + assert representation representation = ifcopenshell.util.representation.resolve_representation(representation) props.booleans.clear() diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index a468b0ddd9..4521fa103a 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -174,7 +174,7 @@ class Geometry(bonsai.core.tool.Geometry): @classmethod def delete_ifc_item(cls, obj: bpy.types.Object) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() if len(props.item_objs) == 1: return for i, item_obj in enumerate(props.item_objs): @@ -1622,7 +1622,7 @@ class Geometry(bonsai.core.tool.Geometry): @classmethod def sync_item_positions(cls) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() if not props.representation_obj: return unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) @@ -1732,7 +1732,7 @@ class Geometry(bonsai.core.tool.Geometry): @classmethod def import_item(cls, obj: bpy.types.Object) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() rep_obj = props.representation_obj tool.Loader.settings.contexts = ifcopenshell.util.representation.get_prioritised_contexts(tool.Ifc.get()) tool.Loader.settings.context_settings = tool.Loader.create_settings() @@ -1792,7 +1792,7 @@ class Geometry(bonsai.core.tool.Geometry): @classmethod def disable_item_mode(cls) -> None: - props = bpy.context.scene.BIMGeometryProperties + props = tool.Geometry.get_geometry_props() if props.representation_obj: props.representation_obj.hide_set(False) cls.unlock_object(props.representation_obj) @@ -1815,7 +1815,9 @@ class Geometry(bonsai.core.tool.Geometry): builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj + props = tool.Geometry.get_geometry_props() + rep_obj = props.representation_obj + assert rep_obj if (coordinate_offset := cls.get_cartesian_point_offset(rep_obj)) is not None: verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] else: diff --git a/src/bonsai/bonsai/tool/surveyor.py b/src/bonsai/bonsai/tool/surveyor.py index 39e781c834..6b9e9d0799 100644 --- a/src/bonsai/bonsai/tool/surveyor.py +++ b/src/bonsai/bonsai/tool/surveyor.py @@ -18,6 +18,8 @@ import bpy import ifcopenshell.api +import ifcopenshell.util.geolocation +import ifcopenshell.util.unit import bonsai.core.tool import bonsai.tool as tool import numpy as np diff --git a/src/bonsai/test/tool/test_geometry.py b/src/bonsai/test/tool/test_geometry.py index 223bd65fb5..f1ca935f30 100644 --- a/src/bonsai/test/tool/test_geometry.py +++ b/src/bonsai/test/tool/test_geometry.py @@ -457,13 +457,13 @@ class TestSelectConnection(NewFile): class TestShouldForceFacetedBrep(NewFile): def test_run(self): - result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep + result = tool.Geometry.get_geometry_props().should_force_faceted_brep assert subject.should_force_faceted_brep() is result class TestShouldForceTriangulation(NewFile): def test_run(self): - result = bpy.context.scene.BIMGeometryProperties.should_force_triangulation + result = tool.Geometry.get_geometry_props().should_force_triangulation assert subject.should_force_triangulation() is result @@ -519,7 +519,7 @@ class TestShouldGenerateUVs(NewFile): class TestShouldUsePresentationStyleAssignment(NewFile): def test_run(self): - result = bpy.context.scene.BIMGeometryProperties.should_use_presentation_style_assignment + result = tool.Geometry.get_geometry_props().should_use_presentation_style_assignment assert subject.should_use_presentation_style_assignment() is result diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 5e56282195..81203c288f 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -1282,7 +1282,7 @@ class ShapeBuilder: ) return points, segments, transition_arc - def mesh(self, points: list[list[float]], faces: list[list[int]]) -> ifcopenshell.entity_instance: + def mesh(self, points: SequenceOfVectors, faces: Sequence[Sequence[int]]) -> ifcopenshell.entity_instance: if self.file.schema == "IFC2X3": return self.faceted_brep(points, faces) return self.polygonal_face_set(points, faces)