This commit is contained in:
Andrej730
2025-05-15 10:40:23 +05:00
parent 76611024b6
commit e4a50b32ce
34 changed files with 813 additions and 451 deletions
@@ -30,6 +30,7 @@ from bpy.props import (
FloatVectorProperty, FloatVectorProperty,
CollectionProperty, CollectionProperty,
) )
from typing import TYPE_CHECKING
class BIMContextProperties(PropertyGroup): class BIMContextProperties(PropertyGroup):
@@ -66,3 +67,10 @@ class BIMContextProperties(PropertyGroup):
) )
active_context_id: IntProperty(name="Active Context Id") active_context_id: IntProperty(name="Active Context Id")
context_attributes: CollectionProperty(name="Context Attributes", type=Attribute) context_attributes: CollectionProperty(name="Context Attributes", type=Attribute)
if TYPE_CHECKING:
contexts: str
subcontexts: str
target_views: str
active_context_id: int
context_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+3 -2
View File
@@ -33,13 +33,14 @@ class BIM_PT_context(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not ContextData.is_loaded: if not ContextData.is_loaded:
ContextData.load() ContextData.load()
props = context.scene.BIMContextProperties assert self.layout
props = tool.Context.get_context_props()
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "contexts", text="") row.prop(props, "contexts", text="")
+2 -2
View File
@@ -90,7 +90,7 @@ def update_cost_item_identification(self: "CostItem", context: bpy.types.Context
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Identification": self.identification}}, **{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Identification": self.identification}},
) )
if props.active_cost_item_id == self.ifc_definition_id: if props.active_cost_item_id == self.ifc_definition_id:
attribute = props.cost_item_attributes.get("Identification") attribute = props.cost_item_attributes["Identification"]
attribute.string_value = self.identification attribute.string_value = self.identification
@@ -105,7 +105,7 @@ def update_cost_item_name(self: "CostItem", context: bpy.types.Context) -> None:
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Name": self.name}}, **{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Name": self.name}},
) )
if props.active_cost_item_id == self.ifc_definition_id: if props.active_cost_item_id == self.ifc_definition_id:
attribute = props.cost_item_attributes.get("Name") attribute = props.cost_item_attributes["Name"]
attribute.string_value = self.name attribute.string_value = self.name
@@ -129,7 +129,9 @@ class Annotator:
def get_annotation_obj( def get_annotation_obj(
drawing: ifcopenshell.entity_instance, object_type: str, data_type: tool.Drawing.ANNOTATION_DATA_TYPE drawing: ifcopenshell.entity_instance, object_type: str, data_type: tool.Drawing.ANNOTATION_DATA_TYPE
) -> bpy.types.Object: ) -> bpy.types.Object:
assert bpy.context.scene
camera = tool.Ifc.get_object(drawing) camera = tool.Ifc.get_object(drawing)
assert isinstance(camera, bpy.types.Object)
# those annotations you want to obey the depth of the 3d cursor # those annotations you want to obey the depth of the 3d cursor
if object_type == "PLAN_LEVEL": if object_type == "PLAN_LEVEL":
co1 = bpy.context.scene.cursor.location.copy() co1 = bpy.context.scene.cursor.location.copy()
@@ -1619,8 +1619,9 @@ class AddAnnotation(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
props = tool.Drawing.get_annotation_props() props = tool.Drawing.get_annotation_props()
if not (drawing := tool.Ifc.get_entity(context.scene.camera)): dprops = tool.Drawing.get_document_props()
self.report({"WARNING"}, "Not a BIM camera") if not (drawing := dprops.get_active_drawing()):
self.report({"WARNING"}, "No active drawing.")
return return
obj = core.add_annotation( obj = core.add_annotation(
@@ -2643,6 +2644,7 @@ class ActivateDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
def parse_filter_query(self, mode: Literal["INCLUDE", "EXCLUDE"], context: bpy.types.Context) -> None: def parse_filter_query(self, mode: Literal["INCLUDE", "EXCLUDE"], context: bpy.types.Context) -> None:
if mode == "INCLUDE": if mode == "INCLUDE":
assert context.scene
objects = context.scene.objects objects = context.scene.objects
elif mode == "EXCLUDE": elif mode == "EXCLUDE":
objects = context.visible_objects objects = context.visible_objects
@@ -3103,6 +3105,7 @@ class OrderTextLiteralDown(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
# Ifc Operator is unnecessary, because suboperator is handling IFC changes.
class AssignSelectedObjectAsProduct(bpy.types.Operator): class AssignSelectedObjectAsProduct(bpy.types.Operator):
bl_idname = "bim.assign_selected_as_product" bl_idname = "bim.assign_selected_as_product"
bl_label = "Assign Selected Object As Product" bl_label = "Assign Selected Object As Product"
@@ -3116,18 +3119,25 @@ class AssignSelectedObjectAsProduct(bpy.types.Operator):
return True return True
def execute(self, context): def execute(self, context):
assert bpy.context.view_layer
objs = context.selected_objects[:] objs = context.selected_objects[:]
obj1 = objs[0] obj1, obj2 = objs
element1 = tool.Ifc.get_entity(obj1) element1 = tool.Ifc.get_entity(obj1)
obj2 = objs[1]
element2 = tool.Ifc.get_entity(obj2) element2 = tool.Ifc.get_entity(obj2)
assert element1 and element2
if element1.is_a("IfcAnnotation"): if element1.is_a("IfcAnnotation"):
other_selected_object = obj2 other_selected_object = obj2
bpy.context.view_layer.objects.active = obj1 bpy.context.view_layer.objects.active = obj1
elif element2.is_a("IfcAnnotation"): elif element2.is_a("IfcAnnotation"):
other_selected_object = obj1 other_selected_object = obj1
bpy.context.view_layer.objects.active = obj2 bpy.context.view_layer.objects.active = obj2
context.active_object.BIMAssignedProductProperties.relating_product = other_selected_object else:
self.report({"ERROR"}, "One of the selected objects must be IfcAnnotation.")
return {"CANCELLED"}
assert (active_obj := context.active_object)
props = tool.Drawing.get_object_assigned_product_props(active_obj)
props.relating_product = other_selected_object
bpy.ops.bim.edit_assigned_product() bpy.ops.bim.edit_assigned_product()
return {"FINISHED"} return {"FINISHED"}
@@ -3139,9 +3149,11 @@ class EditAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
product = None product = None
if context.active_object.BIMAssignedProductProperties.relating_product: assert (obj := context.active_object)
product = tool.Ifc.get_entity(context.active_object.BIMAssignedProductProperties.relating_product) props = tool.Drawing.get_object_assigned_product_props(obj)
core.edit_assigned_product(tool.Ifc, tool.Drawing, obj=context.active_object, product=product) if props.relating_product:
product = tool.Ifc.get_entity(props.relating_product)
core.edit_assigned_product(tool.Ifc, tool.Drawing, obj=obj, product=product)
tool.Blender.update_viewport() tool.Blender.update_viewport()
@@ -3151,6 +3163,7 @@ class EnableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
assert context.active_object
core.enable_editing_assigned_product(tool.Drawing, obj=context.active_object) core.enable_editing_assigned_product(tool.Drawing, obj=context.active_object)
@@ -3160,6 +3173,7 @@ class DisableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
assert context.active_object
core.disable_editing_assigned_product(tool.Drawing, obj=context.active_object) core.disable_editing_assigned_product(tool.Drawing, obj=context.active_object)
@@ -3203,6 +3217,7 @@ class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
document_type: Literal["SHEET", "TITLEBLOCK", "EMBEDDED"] document_type: Literal["SHEET", "TITLEBLOCK", "EMBEDDED"]
def invoke(self, context, event): def invoke(self, context, event):
assert context.window_manager
self.props = tool.Drawing.get_document_props() self.props = tool.Drawing.get_document_props()
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id) sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
if sheet.is_a("IfcDocumentInformation"): if sheet.is_a("IfcDocumentInformation"):
@@ -752,6 +752,12 @@ class LiteralProps(PropertyGroup):
} }
return text_data return text_data
if TYPE_CHECKING:
attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
value: str
box_alignment: str
ifc_definition_id: int
class BIMTextProperties(PropertyGroup): class BIMTextProperties(PropertyGroup):
is_editing: BoolProperty(name="Is Editing", default=False) is_editing: BoolProperty(name="Is Editing", default=False)
@@ -802,6 +808,10 @@ class BIMAssignedProductProperties(PropertyGroup):
is_editing_product: BoolProperty(name="Is Editing Product", default=False) is_editing_product: BoolProperty(name="Is Editing Product", default=False)
relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object, poll=relating_product_poll) relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object, poll=relating_product_poll)
if TYPE_CHECKING:
is_editing_product: bool
relating_product: Union[bpy.types.Object, None]
annotation_classes = [ annotation_classes = [
(x, *tool.Drawing.ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(tool.Drawing.ANNOTATION_TYPES_DATA) (x, *tool.Drawing.ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(tool.Drawing.ANNOTATION_TYPES_DATA)
+5 -3
View File
@@ -494,17 +494,19 @@ class BIM_PT_product_assignments(Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
if not tool.Ifc.get() or not context.active_object: if not tool.Ifc.get() or not context.active_object:
return return False
element = tool.Ifc.get_entity(context.active_object) element = tool.Ifc.get_entity(context.active_object)
if not element: if not element:
return return False
return element.is_a("IfcAnnotation") return element.is_a("IfcAnnotation")
def draw(self, context): def draw(self, context):
if not ProductAssignmentsData.is_loaded: if not ProductAssignmentsData.is_loaded:
ProductAssignmentsData.load() ProductAssignmentsData.load()
props = context.active_object.BIMAssignedProductProperties assert self.layout
assert (obj := context.active_object)
props = tool.Drawing.get_object_assigned_product_props(obj)
if props.is_editing_product: if props.is_editing_product:
row = self.layout.row(align=True) row = self.layout.row(align=True)
+35 -22
View File
@@ -23,6 +23,7 @@ import ifcopenshell.util.placement
import ifcopenshell.util.schema import ifcopenshell.util.schema
import ifcopenshell.util.unit import ifcopenshell.util.unit
import bonsai.tool as tool import bonsai.tool as tool
from typing import Any, Union
from mathutils import Vector from mathutils import Vector
@@ -45,13 +46,12 @@ class ViewportData:
cls.data = {"mode": cls.mode()} cls.data = {"mode": cls.mode()}
@classmethod @classmethod
def mode(cls): def mode(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
obj_mode = ("OBJECT", "IFC Object Mode", "View and move the placements of objects", "OBJECT_DATAMODE", 0) obj_mode = ("OBJECT", "IFC Object Mode", "View and move the placements of objects", "OBJECT_DATAMODE", 0)
item_mode = ("ITEM", "IFC Item Mode", "View individual representation items", "MESH_DATA", 1) item_mode = ("ITEM", "IFC Item Mode", "View individual representation items", "MESH_DATA", 1)
edit_mode = ("EDIT", "IFC Edit Mode", "Edit representation items", "EDITMODE_HLT", 2) edit_mode = ("EDIT", "IFC Edit Mode", "Edit representation items", "EDITMODE_HLT", 2)
obj = bpy.context.active_object obj = bpy.context.active_object
element = tool.Ifc.get_entity(obj)
modes: list[tuple[str, str, str, str, int]] = [obj_mode] modes: list[tuple[str, str, str, str, int]] = [obj_mode]
gprops = tool.Geometry.get_geometry_props() gprops = tool.Geometry.get_geometry_props()
@@ -61,13 +61,14 @@ class ViewportData:
if not obj: if not obj:
return modes return modes
element = tool.Ifc.get_entity(obj)
pprops = tool.Project.get_project_props() pprops = tool.Project.get_project_props()
if obj in pprops.clipping_planes_objs: if obj in pprops.clipping_planes_objs:
pass pass
elif element: elif element:
if tool.Geometry.is_locked(element): if tool.Geometry.is_locked(element):
pass pass
elif obj.data and tool.Geometry.is_profile_based(obj.data): elif obj.data and tool.Geometry.has_mesh_properties(obj.data) and tool.Geometry.is_profile_based(obj.data):
modes.append(edit_mode) modes.append(edit_mode)
elif element.is_a("IfcRelSpaceBoundary"): elif element.is_a("IfcRelSpaceBoundary"):
modes.append(edit_mode) modes.append(edit_mode)
@@ -88,7 +89,7 @@ class ViewportData:
class RepresentationsData: class RepresentationsData:
data = {} data: dict[str, Any] = {}
is_loaded = False is_loaded = False
@classmethod @classmethod
@@ -102,10 +103,12 @@ class RepresentationsData:
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def representations(cls): def representations(cls) -> list[dict[str, Any]]:
results = [] results: list[dict[str, Any]] = []
obj = tool.Geometry.get_active_or_representation_obj() obj = tool.Geometry.get_active_or_representation_obj()
assert obj
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
active_representation_id = None active_representation_id = None
active_representation = tool.Geometry.get_active_representation(obj) active_representation = tool.Geometry.get_active_representation(obj)
@@ -132,8 +135,8 @@ class RepresentationsData:
return results return results
@classmethod @classmethod
def contexts(cls): def contexts(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
results = [] results: list[tuple[str, str, str]] = []
for element in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False): for element in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
results.append((str(element.id()), element.ContextType or "Unnamed", "")) results.append((str(element.id()), element.ContextType or "Unnamed", ""))
for element in tool.Ifc.get().by_type("IfcGeometricRepresentationSubContext", include_subtypes=False): for element in tool.Ifc.get().by_type("IfcGeometricRepresentationSubContext", include_subtypes=False):
@@ -219,9 +222,12 @@ class ConnectionsData:
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def connections(cls): def connections(cls) -> list[dict[str, Any]]:
results = [] results: list[dict[str, Any]] = []
element = tool.Ifc.get_entity(bpy.context.active_object) obj = bpy.context.active_object
assert obj
element = tool.Ifc.get_entity(obj)
assert element
connected_to = getattr(element, "ConnectedTo", []) connected_to = getattr(element, "ConnectedTo", [])
connected_from = getattr(element, "ConnectedFrom", []) connected_from = getattr(element, "ConnectedFrom", [])
@@ -285,13 +291,16 @@ class ConnectionsData:
return results return results
@classmethod @classmethod
def is_connection_realization(cls): def is_connection_realization(cls) -> Union[list[dict[str, Any]], None]:
element = tool.Ifc.get_entity(bpy.context.active_object) obj = bpy.context.active_object
assert obj
element = tool.Ifc.get_entity(obj)
assert element
connections = getattr(element, "IsConnectionRealization", None) connections = getattr(element, "IsConnectionRealization", None)
if not connections: if not connections:
return return
results = [] results: list[dict[str, Any]] = []
for rel in connections: for rel in connections:
data = { data = {
"realizing_elements_connection_type": rel.ConnectionType, "realizing_elements_connection_type": rel.ConnectionType,
@@ -322,16 +331,19 @@ class DerivedCoordinatesData:
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def load_z_values(cls): def load_z_values(cls) -> None:
cls.z_values = [ cls.z_values = [
(bpy.context.active_object.matrix_world @ Vector(co))[2] for co in bpy.context.active_object.bound_box (bpy.context.active_object.matrix_world @ Vector(co))[2] for co in bpy.context.active_object.bound_box
] ]
@classmethod @classmethod
def load_collection(cls): def load_collection(cls) -> None:
cls.collection = None cls.collection = None
cls.collection_z = 0 cls.collection_z = 0
element = tool.Ifc.get_entity(bpy.context.active_object) obj = bpy.context.active_object
if not obj:
return
element = tool.Ifc.get_entity(obj)
if not element: if not element:
return return
parent = ifcopenshell.util.element.get_aggregate(element) parent = ifcopenshell.util.element.get_aggregate(element)
@@ -392,7 +404,7 @@ class PlacementData:
@classmethod @classmethod
def load(cls): def load(cls):
cls.data = {"has_placement": cls.has_placement()} cls.data: dict[str, Any] = {"has_placement": cls.has_placement()}
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
obj = bpy.context.active_object obj = bpy.context.active_object
@@ -415,13 +427,14 @@ class PlacementData:
return False return False
@classmethod @classmethod
def original_xyz(cls, obj): def original_xyz(cls, obj: bpy.types.Object) -> list[float]:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
translation = obj.matrix_world.translation
xyz = ifcopenshell.util.geolocation.xyz2enh( xyz = ifcopenshell.util.geolocation.xyz2enh(
obj.matrix_world[0][3], translation[0],
obj.matrix_world[1][3], translation[1],
obj.matrix_world[2][3], translation[2],
float(props.blender_offset_x) * unit_scale, float(props.blender_offset_x) * unit_scale,
float(props.blender_offset_y) * unit_scale, float(props.blender_offset_y) * unit_scale,
float(props.blender_offset_z) * unit_scale, float(props.blender_offset_z) * unit_scale,
@@ -112,7 +112,9 @@ def update_blender_coordinates(self: "BIMGeoreferenceProperties", context: bpy.t
props.is_updating_coordinates = True props.is_updating_coordinates = True
blender_coordinates = tool.Georeference.get_coordinates("blender") blender_coordinates = tool.Georeference.get_coordinates("blender")
local_coordinates = ifcopenshell.util.geolocation.xyz2enh( local_coordinates = ifcopenshell.util.geolocation.xyz2enh(
*blender_coordinates, blender_coordinates[0],
blender_coordinates[1],
blender_coordinates[2],
float(props.blender_offset_x), float(props.blender_offset_x),
float(props.blender_offset_y), float(props.blender_offset_y),
float(props.blender_offset_z), float(props.blender_offset_z),
+101 -68
View File
@@ -17,7 +17,9 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
from typing import Any, Union
from ifcopenshell.util.doc import get_entity_doc from ifcopenshell.util.doc import get_entity_doc
@@ -31,42 +33,46 @@ def refresh():
class RolesAddressesData: class RolesAddressesData:
@classmethod @classmethod
def get_roles(cls, parent): def get_roles(cls, parent: ifcopenshell.entity_instance) -> list[dict[str, Any]]:
results = [] props = tool.Owner.get_owner_props()
results: list[dict[str, Any]] = []
for role in parent.Roles or []: for role in parent.Roles or []:
results.append( results.append(
{ {
"id": role.id(), "id": role.id(),
"is_editing": bpy.context.scene.BIMOwnerProperties.active_role_id == role.id(), "is_editing": props.active_role_id == role.id(),
"label": role.UserDefinedRole or role.Role, "label": role.UserDefinedRole or role.Role,
"props": bpy.context.scene.BIMOwnerProperties.role_attributes, "props": props.role_attributes,
} }
) )
return results return results
@classmethod @classmethod
def get_addresses(cls, parent): def get_addresses(cls, parent: ifcopenshell.entity_instance) -> list[dict[str, Any]]:
results = [] props = tool.Owner.get_owner_props()
results: list[dict[str, Any]] = []
for address in parent.Addresses or []: for address in parent.Addresses or []:
results.append( results.append(
{ {
"id": address.id(), "id": address.id(),
"is_editing": bpy.context.scene.BIMOwnerProperties.active_address_id == address.id(), "is_editing": props.active_address_id == address.id(),
"label": address.is_a(), "label": address.is_a(),
"props": bpy.context.scene.BIMOwnerProperties.address_attributes, "props": props.address_attributes,
"list_attributes": cls.get_address_list_attributes(address), "list_attributes": cls.get_address_list_attributes(address),
} }
) )
return results return results
@classmethod @classmethod
def get_address_list_attributes(cls, address): def get_address_list_attributes(cls, address: ifcopenshell.entity_instance) -> list[dict[str, Any]]:
results = [] results: list[dict[str, Any]] = []
props = bpy.context.scene.BIMOwnerProperties props = tool.Owner.get_owner_props()
if address.is_a("IfcPostalAddress"): if address.is_a("IfcPostalAddress"):
names = ["AddressLines"] names = ["AddressLines"]
elif address.is_a("IfcTelecomAddress"): elif address.is_a("IfcTelecomAddress"):
names = ["TelephoneNumbers", "FacsimileNumbers", "ElectronicMailAddresses", "MessagingIDs"] names = ["TelephoneNumbers", "FacsimileNumbers", "ElectronicMailAddresses", "MessagingIDs"]
else:
assert False, f"Unexpected entity: {address}"
for name in names: for name in names:
if name == "AddressLines": if name == "AddressLines":
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.address_lines)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.address_lines)]
@@ -78,6 +84,8 @@ class RolesAddressesData:
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.electronic_mail_addresses)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.electronic_mail_addresses)]
elif name == "MessagingIDs": elif name == "MessagingIDs":
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.messaging_ids)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.messaging_ids)]
else:
assert False, f"Unexpected name: {name}"
results.append({"name": name, "items": items}) results.append({"name": name, "items": items})
return results return results
@@ -92,14 +100,15 @@ class PeopleData(RolesAddressesData):
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def get_people(cls): def get_people(cls) -> list[dict[str, Any]]:
people = [] props = tool.Owner.get_owner_props()
people: list[dict[str, Any]] = []
for person in tool.Ifc.get().by_type("IfcPerson"): for person in tool.Ifc.get().by_type("IfcPerson"):
roles = cls.get_roles(person) roles = cls.get_roles(person)
people.append( people.append(
{ {
"id": person.id(), "id": person.id(),
"props": bpy.context.scene.BIMOwnerProperties.person_attributes, "props": props.person_attributes,
"name": cls.get_person_name(person), "name": cls.get_person_name(person),
"roles_label": ", ".join([r["label"] for r in roles]), "roles_label": ", ".join([r["label"] for r in roles]),
"is_editing": cls.get_person_is_editing(person), "is_editing": cls.get_person_is_editing(person),
@@ -112,7 +121,7 @@ class PeopleData(RolesAddressesData):
return people return people
@classmethod @classmethod
def get_person_name(cls, person): def get_person_name(cls, person: ifcopenshell.entity_instance) -> str:
if tool.Ifc.get_schema() == "IFC2X3": if tool.Ifc.get_schema() == "IFC2X3":
name = person.Id name = person.Id
else: else:
@@ -124,20 +133,24 @@ class PeopleData(RolesAddressesData):
return name return name
@classmethod @classmethod
def get_person_is_editing(cls, person): def get_person_is_editing(cls, person: ifcopenshell.entity_instance) -> bool:
return bpy.context.scene.BIMOwnerProperties.active_person_id == person.id() props = tool.Owner.get_owner_props()
return props.active_person_id == person.id()
@classmethod @classmethod
def get_person_list_attributes(cls, person): def get_person_list_attributes(cls, person: ifcopenshell.entity_instance) -> list[dict[str, Any]]:
results = [] results: list[dict[str, Any]] = []
props = bpy.context.scene.BIMOwnerProperties props = tool.Owner.get_owner_props()
for name in ["MiddleNames", "PrefixTitles", "SuffixTitles"]: name: tool.Owner.PersonAttributeType
for name in ("MiddleNames", "PrefixTitles", "SuffixTitles"):
if name == "MiddleNames": if name == "MiddleNames":
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.middle_names)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.middle_names)]
elif name == "PrefixTitles": elif name == "PrefixTitles":
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.prefix_titles)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.prefix_titles)]
elif name == "SuffixTitles": elif name == "SuffixTitles":
items = [{"id": id, "prop": prop} for id, prop in enumerate(props.suffix_titles)] items = [{"id": id, "prop": prop} for id, prop in enumerate(props.suffix_titles)]
else:
assert False, name
results.append({"name": name, "items": items}) results.append({"name": name, "items": items})
return results return results
@@ -152,17 +165,18 @@ class OrganisationsData(RolesAddressesData):
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def get_organisations(cls): def get_organisations(cls) -> list[dict[str, Any]]:
organisations = [] props = tool.Owner.get_owner_props()
organisations: list[dict[str, Any]] = []
for organisation in tool.Ifc.get().by_type("IfcOrganization"): for organisation in tool.Ifc.get().by_type("IfcOrganization"):
roles = cls.get_roles(organisation) roles = cls.get_roles(organisation)
organisations.append( organisations.append(
{ {
"id": organisation.id(), "id": organisation.id(),
"props": bpy.context.scene.BIMOwnerProperties.organisation_attributes, "props": props.organisation_attributes,
"name": organisation.Name, "name": organisation.Name,
"roles_label": ", ".join([r["label"] for r in roles]), "roles_label": ", ".join([r["label"] for r in roles]),
"is_editing": bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id(), "is_editing": props.active_organisation_id == organisation.id(),
"is_engaged": bool(organisation.Engages), "is_engaged": bool(organisation.Engages),
"roles": roles, "roles": roles,
"addresses": cls.get_addresses(organisation), "addresses": cls.get_addresses(organisation),
@@ -186,26 +200,27 @@ class OwnerData:
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
def get_user_person(cls): def get_user_person(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcPerson")] return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcPerson")]
@classmethod @classmethod
def get_user_organisation(cls): def get_user_organisation(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcOrganization")] return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcOrganization")]
@classmethod @classmethod
def can_add_user(cls): def can_add_user(cls) -> bool:
return tool.Ifc.get().by_type("IfcPerson") and tool.Ifc.get().by_type("IfcOrganization") return bool(tool.Ifc.get().by_type("IfcPerson") and tool.Ifc.get().by_type("IfcOrganization"))
@classmethod @classmethod
def get_users(cls): def get_users(cls) -> list[dict[str, Any]]:
results = [] props = tool.Owner.get_owner_props()
results: list[dict[str, Any]] = []
for user in tool.Ifc.get().by_type("IfcPersonAndOrganization"): for user in tool.Ifc.get().by_type("IfcPersonAndOrganization"):
results.append( results.append(
{ {
"id": user.id(), "id": user.id(),
"label": "{} ({})".format(user.ThePerson[0] or "Unnamed", user.TheOrganization[0] or "Unnamed"), "label": "{} ({})".format(user.ThePerson[0] or "Unnamed", user.TheOrganization[0] or "Unnamed"),
"is_active": bpy.context.scene.BIMOwnerProperties.active_user_id == user.id(), "is_active": props.active_user_id == user.id(),
} }
) )
return results return results
@@ -224,48 +239,60 @@ class ActorData:
cls.data["actors"] = cls.actors() cls.data["actors"] = cls.actors()
@classmethod @classmethod
def the_actor(cls): def the_actor(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not (ifc_class := bpy.context.scene.BIMOwnerProperties.actor_type): props = tool.Owner.get_owner_props()
if not (ifc_class := props.actor_type):
ifc_class = cls.actor_type()[0][0] ifc_class = cls.actor_type()[0][0]
return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type(ifc_class)] return [(str(p.id()), p[0] or "Unnamed", "") for p in tool.Ifc.get().by_type(ifc_class)]
@classmethod @classmethod
def actors(cls): def actors(cls) -> list[dict[str, Any]]:
actors = [] actors: list[dict[str, Any]] = []
props = bpy.context.scene.BIMOwnerProperties props = tool.Owner.get_owner_props()
for actor in tool.Ifc.get().by_type(props.actor_class, include_subtypes=False): for actor in tool.Ifc.get().by_type(props.actor_class, include_subtypes=False):
is_editing = props.active_actor_id == actor.id() is_editing = props.active_actor_id == actor.id()
if actor.TheActor.is_a("IfcPerson"): the_actor: ifcopenshell.entity_instance = actor.TheActor
the_actor = actor.TheActor.Identification or "N/A" if the_actor.is_a("IfcPerson"):
elif actor.TheActor.is_a("IfcOrganization"): the_actor_ = the_actor.Identification or "N/A"
the_actor = actor.TheActor.Identification or "N/A" elif the_actor.is_a("IfcOrganization"):
elif actor.TheActor.is_a("IfcPersonAndOrganization"): the_actor_ = the_actor.Identification or "N/A"
the_actor = actor.TheActor.ThePerson.Identification or "N/A" elif the_actor.is_a("IfcPersonAndOrganization"):
the_actor += "-" + actor.TheActor.TheOrganization.Identification or "N/A" the_actor_ = the_actor.ThePerson.Identification or "N/A"
the_actor_ += "-" + the_actor.TheOrganization.Identification or "N/A"
else:
assert False, the_actor
actors.append( actors.append(
{"id": actor.id(), "name": actor.Name or "Unnamed", "the_actor": the_actor, "is_editing": is_editing} {
"id": actor.id(),
"name": actor.Name or "Unnamed",
"the_actor": the_actor_,
"is_editing": is_editing,
}
) )
return actors return actors
@classmethod @classmethod
def actor_class(cls) -> list[tuple[str, str, str]]: def actor_class(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
version = tool.Ifc.get_schema() version = tool.Ifc.get_schema()
actor_doc = get_entity_doc(version, "IfcActor")
occupant_doc = get_entity_doc(version, "IfcOccupant")
assert actor_doc and occupant_doc
return [ return [
("IfcActor", "Actor", get_entity_doc(version, "IfcActor").get("description", "")), ("IfcActor", "Actor", actor_doc.get("description", "")),
("IfcOccupant", "Occupant", get_entity_doc(version, "IfcOccupant").get("description", "")), ("IfcOccupant", "Occupant", occupant_doc.get("description", "")),
] ]
@classmethod @classmethod
def actor_type(cls) -> list[tuple[str, str, str]]: def actor_type(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
version = tool.Ifc.get_schema() version = tool.Ifc.get_schema()
person_doc = get_entity_doc(version, "IfcPerson")
organization_doc = get_entity_doc(version, "IfcOrganization")
pao_doc = get_entity_doc(version, "IfcPersonAndOrganization")
assert person_doc and organization_doc and pao_doc
return [ return [
("IfcPerson", "Person", get_entity_doc(version, "IfcPerson").get("description", "")), ("IfcPerson", "Person", person_doc.get("description", "")),
("IfcOrganization", "Organisation", get_entity_doc(version, "IfcOrganization").get("description", "")), ("IfcOrganization", "Organisation", organization_doc.get("description", "")),
( ("IfcPersonAndOrganization", "User", pao_doc.get("description", "")),
"IfcPersonAndOrganization",
"User",
get_entity_doc(version, "IfcPersonAndOrganization").get("description", ""),
),
] ]
@@ -279,25 +306,31 @@ class ObjectActorData:
cls.data = {"actor": cls.actor(), "actors": cls.actors()} cls.data = {"actor": cls.actor(), "actors": cls.actors()}
@classmethod @classmethod
def actor(cls): def actor(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
return [(str(p.id()), p.Name or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcActor")] return [(str(p.id()), p.Name or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcActor")]
@classmethod @classmethod
def actors(cls): def actors(cls) -> list[dict[str, Any]]:
results = [] results: list[dict[str, Any]] = []
element = tool.Ifc.get_entity(bpy.context.active_object) obj = bpy.context.active_object
if not obj:
return results
element = tool.Ifc.get_entity(obj)
if not element: if not element:
return results return results
for rel in getattr(element, "HasAssignments", []): for rel in getattr(element, "HasAssignments", []):
if rel.is_a("IfcRelAssignsToActor"): if rel.is_a("IfcRelAssignsToActor"):
actor = rel.RelatingActor actor = rel.RelatingActor
if actor.TheActor.is_a("IfcPerson"): the_actor: ifcopenshell.entity_instance = actor.TheActor
roles = cls.get_roles(actor.TheActor) if the_actor.is_a("IfcPerson"):
elif actor.TheActor.is_a("IfcOrganization"): roles = cls.get_roles(the_actor)
roles = cls.get_roles(actor.TheActor) elif the_actor.is_a("IfcOrganization"):
elif actor.TheActor.is_a("IfcPersonAndOrganization"): roles = cls.get_roles(the_actor)
roles = cls.get_roles(actor.TheActor.ThePerson) elif the_actor.is_a("IfcPersonAndOrganization"):
roles.extend(cls.get_roles(actor.TheActor.TheOrganization)) roles = cls.get_roles(the_actor.ThePerson)
roles.extend(cls.get_roles(the_actor.TheOrganization))
else:
assert False, the_actor
role = ", ".join(roles) role = ", ".join(roles)
results.append( results.append(
{"id": actor.id(), "name": actor.Name or "Unnamed", "role": role, "ifc_class": actor.is_a()} {"id": actor.id(), "name": actor.Name or "Unnamed", "role": role, "ifc_class": actor.is_a()}
@@ -305,5 +338,5 @@ class ObjectActorData:
return results return results
@classmethod @classmethod
def get_roles(cls, parent): def get_roles(cls, parent: ifcopenshell.entity_instance) -> list[Union[str, None]]:
return [r.UserDefinedRole or r.Role for r in parent.Roles or []] return [r.UserDefinedRole or r.Role for r in parent.Roles or []]
+162 -65
View File
@@ -19,25 +19,35 @@
import bpy import bpy
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.owner as core import bonsai.core.owner as core
from ifcopenshell.api.owner.add_address import ADDRESS_TYPE
from typing import TYPE_CHECKING, get_args
if TYPE_CHECKING:
import bpy._typing.rna_enums as rna_enums
class EnableEditingPerson(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingPerson(bpy.types.Operator):
bl_idname = "bim.enable_editing_person" bl_idname = "bim.enable_editing_person"
bl_label = "Enable Editing Person" bl_label = "Enable Editing Person"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
person: bpy.props.IntProperty() person: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
person: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.enable_editing_person(tool.Owner, person=tool.Ifc.get().by_id(self.person)) core.enable_editing_person(tool.Owner, person=tool.Ifc.get().by_id(self.person))
return {"FINISHED"}
class DisableEditingPerson(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingPerson(bpy.types.Operator):
bl_idname = "bim.disable_editing_person" bl_idname = "bim.disable_editing_person"
bl_label = "Disable Editing Person" bl_label = "Disable Editing Person"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.disable_editing_person(tool.Owner) core.disable_editing_person(tool.Owner)
return {"FINISHED"}
class AddPerson(bpy.types.Operator, tool.Ifc.Operator): class AddPerson(bpy.types.Operator, tool.Ifc.Operator):
@@ -45,7 +55,7 @@ class AddPerson(bpy.types.Operator, tool.Ifc.Operator):
bl_label = "Add Person" bl_label = "Add Person"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context) -> None:
core.add_person(tool.Ifc) core.add_person(tool.Ifc)
@@ -62,57 +72,81 @@ class RemovePerson(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_person" bl_idname = "bim.remove_person"
bl_label = "Remove Person" bl_label = "Remove Person"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
person: bpy.props.IntProperty() person: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
person: int
def _execute(self, context): def _execute(self, context):
core.remove_person(tool.Ifc, person=tool.Ifc.get().by_id(self.person)) core.remove_person(tool.Ifc, person=tool.Ifc.get().by_id(self.person))
class AddPersonAttribute(bpy.types.Operator, tool.Ifc.Operator): class AddPersonAttribute(bpy.types.Operator):
bl_idname = "bim.add_person_attribute" bl_idname = "bim.add_person_attribute"
bl_label = "Add Person Attribute" bl_label = "Add Person Attribute"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty() name: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
items=tuple((i, i, "") for i in get_args(tool.Owner.PersonAttributeType)),
)
def _execute(self, context): if TYPE_CHECKING:
name: tool.Owner.PersonAttributeType # pyright: ignore[reportIncompatibleVariableOverride]
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.add_person_attribute(tool.Owner, name=self.name) core.add_person_attribute(tool.Owner, name=self.name)
return {"FINISHED"}
class RemovePersonAttribute(bpy.types.Operator, tool.Ifc.Operator): class RemovePersonAttribute(bpy.types.Operator):
bl_idname = "bim.remove_person_attribute" bl_idname = "bim.remove_person_attribute"
bl_label = "Remove Person Attribute" bl_label = "Remove Person Attribute"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty() name: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
id: bpy.props.IntProperty() items=tuple((i, i, "") for i in get_args(tool.Owner.PersonAttributeType)),
)
id: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
name: tool.Owner.PersonAttributeType # pyright: ignore[reportIncompatibleVariableOverride]
id: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.remove_person_attribute(tool.Owner, name=self.name, id=self.id) core.remove_person_attribute(tool.Owner, name=self.name, id=self.id)
return {"FINISHED"}
class EnableEditingRole(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingRole(bpy.types.Operator):
bl_idname = "bim.enable_editing_role" bl_idname = "bim.enable_editing_role"
bl_label = "Enable Editing Role" bl_label = "Enable Editing Role"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
role: bpy.props.IntProperty() role: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
role: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.enable_editing_role(tool.Owner, role=tool.Ifc.get().by_id(self.role)) core.enable_editing_role(tool.Owner, role=tool.Ifc.get().by_id(self.role))
return {"FINISHED"}
class DisableEditingRole(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingRole(bpy.types.Operator):
bl_idname = "bim.disable_editing_role" bl_idname = "bim.disable_editing_role"
bl_label = "Disable Editing Role" bl_label = "Disable Editing Role"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.disable_editing_role(tool.Owner) core.disable_editing_role(tool.Owner)
return {"FINISHED"}
class AddRole(bpy.types.Operator, tool.Ifc.Operator): class AddRole(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_role" bl_idname = "bim.add_role"
bl_label = "Add Role" bl_label = "Add Role"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
parent: bpy.props.IntProperty() parent: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
parent: int
def _execute(self, context): def _execute(self, context):
core.add_role(tool.Ifc, parent=tool.Ifc.get().by_id(self.parent)) core.add_role(tool.Ifc, parent=tool.Ifc.get().by_id(self.parent))
@@ -131,7 +165,10 @@ class RemoveRole(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_role" bl_idname = "bim.remove_role"
bl_label = "Remove Role" bl_label = "Remove Role"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
role: bpy.props.IntProperty() role: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
role: int
def _execute(self, context): def _execute(self, context):
core.remove_role(tool.Ifc, role=tool.Ifc.get().by_id(self.role)) core.remove_role(tool.Ifc, role=tool.Ifc.get().by_id(self.role))
@@ -141,51 +178,74 @@ class AddAddress(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_address" bl_idname = "bim.add_address"
bl_label = "Add Address" bl_label = "Add Address"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
parent: bpy.props.IntProperty() parent: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
ifc_class: bpy.props.StringProperty() ifc_class: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
items=tuple((i, i, "") for i in get_args(ADDRESS_TYPE)),
)
if TYPE_CHECKING:
parent: int
ifc_class: ADDRESS_TYPE
def _execute(self, context): def _execute(self, context):
core.add_address(tool.Ifc, parent=tool.Ifc.get().by_id(self.parent), ifc_class=self.ifc_class) core.add_address(tool.Ifc, parent=tool.Ifc.get().by_id(self.parent), ifc_class=self.ifc_class)
class AddAddressAttribute(bpy.types.Operator, tool.Ifc.Operator): class AddAddressAttribute(bpy.types.Operator):
bl_idname = "bim.add_address_attribute" bl_idname = "bim.add_address_attribute"
bl_label = "Add Address Attribute" bl_label = "Add Address Attribute"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty() name: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
items=tuple((i, i, "") for i in get_args(tool.Owner.AddressAttributeType)),
)
def _execute(self, context): if TYPE_CHECKING:
name: tool.Owner.AddressAttributeType # pyright: ignore[reportIncompatibleVariableOverride]
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.add_address_attribute(tool.Owner, name=self.name) core.add_address_attribute(tool.Owner, name=self.name)
return {"FINISHED"}
class RemoveAddressAttribute(bpy.types.Operator, tool.Ifc.Operator): class RemoveAddressAttribute(bpy.types.Operator):
bl_idname = "bim.remove_address_attribute" bl_idname = "bim.remove_address_attribute"
bl_label = "Remove Address Attribute" bl_label = "Remove Address Attribute"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty() name: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
id: bpy.props.IntProperty() items=tuple((i, i, "") for i in get_args(tool.Owner.AddressAttributeType)),
)
def _execute(self, context): if TYPE_CHECKING:
name: tool.Owner.AddressAttributeType # pyright: ignore[reportIncompatibleVariableOverride]
id: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.remove_address_attribute(tool.Owner, name=self.name, id=self.id) core.remove_address_attribute(tool.Owner, name=self.name, id=self.id)
return {"FINISHED"}
class EnableEditingAddress(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingAddress(bpy.types.Operator):
bl_idname = "bim.enable_editing_address" bl_idname = "bim.enable_editing_address"
bl_label = "Enable Editing Address" bl_label = "Enable Editing Address"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
address: bpy.props.IntProperty() address: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
address: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.enable_editing_address(tool.Owner, address=tool.Ifc.get().by_id(self.address)) core.enable_editing_address(tool.Owner, address=tool.Ifc.get().by_id(self.address))
return {"FINISHED"}
class DisableEditingAddress(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingAddress(bpy.types.Operator):
bl_idname = "bim.disable_editing_address" bl_idname = "bim.disable_editing_address"
bl_label = "Disable Editing Address" bl_label = "Disable Editing Address"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.disable_editing_address(tool.Owner) core.disable_editing_address(tool.Owner)
return {"FINISHED"}
class EditAddress(bpy.types.Operator, tool.Ifc.Operator): class EditAddress(bpy.types.Operator, tool.Ifc.Operator):
@@ -201,29 +261,37 @@ class RemoveAddress(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_address" bl_idname = "bim.remove_address"
bl_label = "Remove Address" bl_label = "Remove Address"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
address: bpy.props.IntProperty() address: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
address: int
def _execute(self, context): def _execute(self, context):
core.remove_address(tool.Ifc, address=tool.Ifc.get().by_id(self.address)) core.remove_address(tool.Ifc, address=tool.Ifc.get().by_id(self.address))
class EnableEditingOrganisation(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingOrganisation(bpy.types.Operator):
bl_idname = "bim.enable_editing_organisation" bl_idname = "bim.enable_editing_organisation"
bl_label = "Enable Editing Organisation" bl_label = "Enable Editing Organisation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
organisation: bpy.props.IntProperty() organisation: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
organisation: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.enable_editing_organisation(tool.Owner, organisation=tool.Ifc.get().by_id(self.organisation)) core.enable_editing_organisation(tool.Owner, organisation=tool.Ifc.get().by_id(self.organisation))
return {"FINISHED"}
class DisableEditingOrganisation(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingOrganisation(bpy.types.Operator):
bl_idname = "bim.disable_editing_organisation" bl_idname = "bim.disable_editing_organisation"
bl_label = "Disable Editing Organisation" bl_label = "Disable Editing Organisation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.disable_editing_organisation(tool.Owner) core.disable_editing_organisation(tool.Owner)
return {"FINISHED"}
class AddOrganisation(bpy.types.Operator, tool.Ifc.Operator): class AddOrganisation(bpy.types.Operator, tool.Ifc.Operator):
@@ -248,7 +316,10 @@ class RemoveOrganisation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_organisation" bl_idname = "bim.remove_organisation"
bl_label = "Remove Organisation" bl_label = "Remove Organisation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
organisation: bpy.props.IntProperty() organisation: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
organisation: int
def _execute(self, context): def _execute(self, context):
core.remove_organisation(tool.Ifc, tool.Ifc.get().by_id(self.organisation)) core.remove_organisation(tool.Ifc, tool.Ifc.get().by_id(self.organisation))
@@ -258,8 +329,12 @@ class AddPersonAndOrganisation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_person_and_organisation" bl_idname = "bim.add_person_and_organisation"
bl_label = "Add Person And Organisation" bl_label = "Add Person And Organisation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
person: bpy.props.IntProperty() person: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
organisation: bpy.props.IntProperty() organisation: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
person: int
organisation: int
def _execute(self, context): def _execute(self, context):
core.add_person_and_organisation( core.add_person_and_organisation(
@@ -271,7 +346,10 @@ class RemovePersonAndOrganisation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_person_and_organisation" bl_idname = "bim.remove_person_and_organisation"
bl_label = "Remove Person And Organisation" bl_label = "Remove Person And Organisation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
person_and_organisation: bpy.props.IntProperty() person_and_organisation: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
person_and_organisation: int
def _execute(self, context): def _execute(self, context):
core.remove_person_and_organisation( core.remove_person_and_organisation(
@@ -279,24 +357,29 @@ class RemovePersonAndOrganisation(bpy.types.Operator, tool.Ifc.Operator):
) )
class SetUser(bpy.types.Operator, tool.Ifc.Operator): class SetUser(bpy.types.Operator):
bl_idname = "bim.set_user" bl_idname = "bim.set_user"
bl_label = "Set User" bl_label = "Set User"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
user: bpy.props.IntProperty() user: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
user: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.set_user(tool.Owner, user=tool.Ifc.get().by_id(self.user)) core.set_user(tool.Owner, user=tool.Ifc.get().by_id(self.user))
return {"FINISHED"}
class ClearUser(bpy.types.Operator, tool.Ifc.Operator): class ClearUser(bpy.types.Operator):
bl_idname = "bim.clear_user" bl_idname = "bim.clear_user"
bl_label = "Clear User" bl_label = "Clear User"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
user: bpy.props.IntProperty() user: bpy.props.IntProperty()
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.clear_user(tool.Owner) core.clear_user(tool.Owner)
return {"FINISHED"}
class AddActor(bpy.types.Operator, tool.Ifc.Operator): class AddActor(bpy.types.Operator, tool.Ifc.Operator):
@@ -305,28 +388,33 @@ class AddActor(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
props = bpy.context.scene.BIMOwnerProperties props = tool.Owner.get_owner_props()
if props.the_actor: if props.the_actor:
core.add_actor(tool.Ifc, ifc_class=props.actor_class, actor=tool.Ifc.get().by_id(int(props.the_actor))) core.add_actor(tool.Ifc, ifc_class=props.actor_class, actor=tool.Ifc.get().by_id(int(props.the_actor)))
class EnableEditingActor(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingActor(bpy.types.Operator):
bl_idname = "bim.enable_editing_actor" bl_idname = "bim.enable_editing_actor"
bl_label = "Enable Editing Actor" bl_label = "Enable Editing Actor"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
actor: bpy.props.IntProperty() actor: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
def _execute(self, context): if TYPE_CHECKING:
actor: int
def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.enable_editing_actor(tool.Owner, actor=tool.Ifc.get().by_id(self.actor)) core.enable_editing_actor(tool.Owner, actor=tool.Ifc.get().by_id(self.actor))
return {"FINISHED"}
class DisableEditingActor(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingActor(bpy.types.Operator):
bl_idname = "bim.disable_editing_actor" bl_idname = "bim.disable_editing_actor"
bl_label = "Disable Editing Actor" bl_label = "Disable Editing Actor"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
core.disable_editing_actor(tool.Owner) core.disable_editing_actor(tool.Owner)
return {"FINISHED"}
class EditActor(bpy.types.Operator, tool.Ifc.Operator): class EditActor(bpy.types.Operator, tool.Ifc.Operator):
@@ -342,7 +430,10 @@ class RemoveActor(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_actor" bl_idname = "bim.remove_actor"
bl_label = "Remove Actor" bl_label = "Remove Actor"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
actor: bpy.props.IntProperty() actor: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
actor: int
def _execute(self, context): def _execute(self, context):
core.remove_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor)) core.remove_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor))
@@ -352,21 +443,27 @@ class AssignActor(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_actor" bl_idname = "bim.assign_actor"
bl_label = "Assign Actor" bl_label = "Assign Actor"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
actor: bpy.props.IntProperty() actor: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
actor: int
def _execute(self, context): def _execute(self, context):
core.assign_actor( assert (obj := context.active_object)
tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=tool.Ifc.get_entity(context.active_object) assert (element := tool.Ifc.get_entity(obj))
) core.assign_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=element)
class UnassignActor(bpy.types.Operator, tool.Ifc.Operator): class UnassignActor(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_actor" bl_idname = "bim.unassign_actor"
bl_label = "Unassign Actor" bl_label = "Unassign Actor"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
actor: bpy.props.IntProperty() actor: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
if TYPE_CHECKING:
actor: int
def _execute(self, context): def _execute(self, context):
core.unassign_actor( assert (obj := context.active_object)
tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=tool.Ifc.get_entity(context.active_object) assert (element := tool.Ifc.get_entity(obj))
) core.unassign_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=element)
+36 -8
View File
@@ -20,6 +20,7 @@ import bpy
import bonsai.tool as tool import bonsai.tool as tool
from bonsai.bim.prop import StrProperty, Attribute from bonsai.bim.prop import StrProperty, Attribute
from bonsai.bim.module.owner.data import OwnerData, ActorData, ObjectActorData from bonsai.bim.module.owner.data import OwnerData, ActorData, ObjectActorData
from typing import TYPE_CHECKING, Literal
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -33,45 +34,45 @@ from bpy.props import (
) )
def get_user_person(self, context): def get_user_person(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not OwnerData.is_loaded: if not OwnerData.is_loaded:
OwnerData.load() OwnerData.load()
return OwnerData.data["user_person"] return OwnerData.data["user_person"]
def get_user_organisation(self, context): def get_user_organisation(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not OwnerData.is_loaded: if not OwnerData.is_loaded:
OwnerData.load() OwnerData.load()
return OwnerData.data["user_organisation"] return OwnerData.data["user_organisation"]
def get_the_actor(self, context): def get_the_actor(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ActorData.is_loaded: if not ActorData.is_loaded:
ActorData.load() ActorData.load()
return ActorData.data["the_actor"] return ActorData.data["the_actor"]
def get_actor(self, context): def get_actor(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ObjectActorData.is_loaded: if not ObjectActorData.is_loaded:
ObjectActorData.load() ObjectActorData.load()
return ObjectActorData.data["actor"] return ObjectActorData.data["actor"]
def update_actor_type(self, context): def update_actor_type(self: "BIMOwnerProperties", context: bpy.types.Context) -> None:
ActorData.data["the_actor"] = ActorData.the_actor() ActorData.data["the_actor"] = ActorData.the_actor()
def update_actor_class(self, context): def update_actor_class(self: "BIMOwnerProperties", context: bpy.types.Context) -> None:
ActorData.data["actors"] = ActorData.actors() ActorData.data["actors"] = ActorData.actors()
def get_actor_class(self, context): def get_actor_class(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ActorData.is_loaded: if not ActorData.is_loaded:
ActorData.load() ActorData.load()
return ActorData.data["actor_class"] return ActorData.data["actor_class"]
def get_actor_type(self, context): def get_actor_type(self: "BIMOwnerProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ActorData.is_loaded: if not ActorData.is_loaded:
ActorData.load() ActorData.load()
return ActorData.data["actor_type"] return ActorData.data["actor_type"]
@@ -119,3 +120,30 @@ class BIMOwnerProperties(PropertyGroup):
items=get_the_actor, name="Actor", description="This entity represents an individual human being." items=get_the_actor, name="Actor", description="This entity represents an individual human being."
) )
actor: EnumProperty(items=get_actor, name="Actor") actor: EnumProperty(items=get_actor, name="Actor")
if TYPE_CHECKING:
active_person_id: int
person_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
middle_names: bpy.types.bpy_prop_collection_idprop[StrProperty]
prefix_titles: bpy.types.bpy_prop_collection_idprop[StrProperty]
suffix_titles: bpy.types.bpy_prop_collection_idprop[StrProperty]
active_organisation_id: int
organisation_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
active_role_id: int
role_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
active_address_id: int
address_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
address_lines: bpy.types.bpy_prop_collection_idprop[StrProperty]
telephone_numbers: bpy.types.bpy_prop_collection_idprop[StrProperty]
facsimile_numbers: bpy.types.bpy_prop_collection_idprop[StrProperty]
electronic_mail_addresses: bpy.types.bpy_prop_collection_idprop[StrProperty]
messaging_ids: bpy.types.bpy_prop_collection_idprop[StrProperty]
user_person: str
user_organisation: str
active_user_id: int
active_actor_id: int
actor_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
actor_class: Literal["IfcActor", "IfcOccupant"]
actor_type: str
the_actor: str
actor: str
+22 -13
View File
@@ -19,10 +19,11 @@
import bpy import bpy
import bonsai.bim.helper import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
from typing import Any
from bonsai.bim.module.owner.data import PeopleData, OrganisationsData, OwnerData, ActorData, ObjectActorData from bonsai.bim.module.owner.data import PeopleData, OrganisationsData, OwnerData, ActorData, ObjectActorData
def draw_roles(box, parent): def draw_roles(box: bpy.types.UILayout, parent: dict[str, Any]) -> None:
row = box.row(align=True) row = box.row(align=True)
row.label(text="Roles") row.label(text="Roles")
op = row.operator("bim.add_role", icon="ADD", text="") op = row.operator("bim.add_role", icon="ADD", text="")
@@ -41,7 +42,7 @@ def draw_roles(box, parent):
row.operator("bim.remove_role", icon="X", text="").role = role["id"] row.operator("bim.remove_role", icon="X", text="").role = role["id"]
def draw_addresses(box, parent): def draw_addresses(box: bpy.types.UILayout, parent: dict[str, Any]) -> None:
row = box.row(align=True) row = box.row(align=True)
row.label(text="Addresses") row.label(text="Addresses")
op = row.operator("bim.add_address", icon="LINK_BLEND", text="") op = row.operator("bim.add_address", icon="LINK_BLEND", text="")
@@ -87,12 +88,13 @@ class BIM_PT_people(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not PeopleData.is_loaded: if not PeopleData.is_loaded:
PeopleData.load() PeopleData.load()
assert self.layout
self.layout.use_property_split = True self.layout.use_property_split = True
self.layout.use_property_decorate = False self.layout.use_property_decorate = False
@@ -102,7 +104,8 @@ class BIM_PT_people(bpy.types.Panel):
for person in PeopleData.data["people"]: for person in PeopleData.data["people"]:
self.draw_person(person) self.draw_person(person)
def draw_person(self, person): def draw_person(self, person: dict[str, Any]) -> None:
assert self.layout
if person["is_editing"]: if person["is_editing"]:
box = self.layout.box() box = self.layout.box()
row = box.row(align=True) row = box.row(align=True)
@@ -146,12 +149,13 @@ class BIM_PT_organisations(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not OrganisationsData.is_loaded: if not OrganisationsData.is_loaded:
OrganisationsData.load() OrganisationsData.load()
assert self.layout
self.layout.use_property_split = True self.layout.use_property_split = True
self.layout.use_property_decorate = False self.layout.use_property_decorate = False
@@ -161,7 +165,8 @@ class BIM_PT_organisations(bpy.types.Panel):
for organisation in OrganisationsData.data["organisations"]: for organisation in OrganisationsData.data["organisations"]:
self.draw_organisation(organisation) self.draw_organisation(organisation)
def draw_organisation(self, organisation): def draw_organisation(self, organisation: dict[str, Any]) -> None:
assert self.layout
if organisation["is_editing"]: if organisation["is_editing"]:
box = self.layout.box() box = self.layout.box()
row = box.row(align=True) row = box.row(align=True)
@@ -193,15 +198,16 @@ class BIM_PT_owner(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not OwnerData.is_loaded: if not OwnerData.is_loaded:
OwnerData.load() OwnerData.load()
assert self.layout
self.layout.use_property_split = True self.layout.use_property_split = True
self.layout.use_property_decorate = False self.layout.use_property_decorate = False
props = context.scene.BIMOwnerProperties props = tool.Owner.get_owner_props()
if not OwnerData.data["user_person"]: if not OwnerData.data["user_person"]:
self.layout.label(text="No people found.") self.layout.label(text="No people found.")
@@ -244,13 +250,14 @@ class BIM_PT_actor(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not ActorData.is_loaded: if not ActorData.is_loaded:
ActorData.load() ActorData.load()
self.props = context.scene.BIMOwnerProperties assert self.layout
self.props = tool.Owner.get_owner_props()
self.layout.use_property_split = True self.layout.use_property_split = True
self.layout.use_property_decorate = False self.layout.use_property_decorate = False
@@ -268,7 +275,8 @@ class BIM_PT_actor(bpy.types.Panel):
for actor in ActorData.data["actors"]: for actor in ActorData.data["actors"]:
self.draw_actor(actor) self.draw_actor(actor)
def draw_actor(self, actor): def draw_actor(self, actor: dict[str, Any]) -> None:
assert self.layout
if actor["is_editing"]: if actor["is_editing"]:
box = self.layout.box() box = self.layout.box()
row = box.row(align=True) row = box.row(align=True)
@@ -295,13 +303,14 @@ class BIM_PT_object_actor(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Ifc.get() return bool(tool.Ifc.get())
def draw(self, context): def draw(self, context):
if not ObjectActorData.is_loaded: if not ObjectActorData.is_loaded:
ObjectActorData.load() ObjectActorData.load()
self.props = context.scene.BIMOwnerProperties assert self.layout
self.props = tool.Owner.get_owner_props()
if not ObjectActorData.data["actor"]: if not ObjectActorData.data["actor"]:
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -58,7 +58,7 @@ def updateResourceName(self, context):
attributes={"Name": self.name}, attributes={"Name": self.name},
) )
if props.active_resource_id == self.ifc_definition_id: if props.active_resource_id == self.ifc_definition_id:
attribute = props.resource_attributes.get("Name") attribute = props.resource_attributes["Name"]
attribute.string_value = self.name attribute.string_value = self.name
bonsai.bim.module.resource.data.refresh() bonsai.bim.module.resource.data.refresh()
tool.Sequence.refresh_task_resources() tool.Sequence.refresh_task_resources()
+40 -36
View File
@@ -27,167 +27,171 @@ if TYPE_CHECKING:
from ifcopenshell.api.owner.add_actor import ACTOR_TYPE from ifcopenshell.api.owner.add_actor import ACTOR_TYPE
def add_person(ifc: tool.Ifc) -> ifcopenshell.entity_instance: def add_person(ifc: type[tool.Ifc]) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_person") return ifc.run("owner.add_person")
def remove_person(ifc: tool.Ifc, person: ifcopenshell.entity_instance) -> None: def remove_person(ifc: type[tool.Ifc], person: ifcopenshell.entity_instance) -> None:
ifc.run("owner.remove_person", person=person) ifc.run("owner.remove_person", person=person)
def enable_editing_person(owner: tool.Owner, person: ifcopenshell.entity_instance) -> None: def enable_editing_person(owner: type[tool.Owner], person: ifcopenshell.entity_instance) -> None:
owner.set_person(person) owner.set_person(person)
owner.import_person_attributes() owner.import_person_attributes()
def disable_editing_person(owner: tool.Owner) -> None: def disable_editing_person(owner: type[tool.Owner]) -> None:
owner.clear_person() owner.clear_person()
def edit_person(ifc: tool.Ifc, owner: tool.Owner) -> None: def edit_person(ifc: type[tool.Ifc], owner: type[tool.Owner]) -> None:
ifc.run("owner.edit_person", person=owner.get_person(), attributes=owner.export_person_attributes()) ifc.run("owner.edit_person", person=owner.get_person(), attributes=owner.export_person_attributes())
disable_editing_person(owner) disable_editing_person(owner)
def add_person_attribute(owner: tool.Owner, name: str) -> None: def add_person_attribute(owner: type[tool.Owner], name: tool.Owner.PersonAttributeType) -> None:
owner.add_person_attribute(name) owner.add_person_attribute(name)
def remove_person_attribute(owner: tool.Owner, name: str, id: int) -> None: def remove_person_attribute(owner: type[tool.Owner], name: tool.Owner.PersonAttributeType, id: int) -> None:
owner.remove_person_attribute(name, id) owner.remove_person_attribute(name, id)
def add_role(ifc: tool.Ifc, parent: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: def add_role(ifc: type[tool.Ifc], parent: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_role", assigned_object=parent) return ifc.run("owner.add_role", assigned_object=parent)
def remove_role(ifc: tool.Ifc, role: ifcopenshell.entity_instance) -> None: def remove_role(ifc: type[tool.Ifc], role: ifcopenshell.entity_instance) -> None:
ifc.run("owner.remove_role", role=role) ifc.run("owner.remove_role", role=role)
def enable_editing_role(owner: tool.Owner, role: ifcopenshell.entity_instance) -> None: def enable_editing_role(owner: type[tool.Owner], role: ifcopenshell.entity_instance) -> None:
owner.set_role(role) owner.set_role(role)
owner.import_role_attributes() owner.import_role_attributes()
def disable_editing_role(owner: tool.Owner) -> None: def disable_editing_role(owner: type[tool.Owner]) -> None:
owner.clear_role() owner.clear_role()
def edit_role(ifc: tool.Ifc, owner: tool.Owner) -> None: def edit_role(ifc: type[tool.Ifc], owner: type[tool.Owner]) -> None:
ifc.run("owner.edit_role", role=owner.get_role(), attributes=owner.export_role_attributes()) ifc.run("owner.edit_role", role=owner.get_role(), attributes=owner.export_role_attributes())
owner.clear_role() owner.clear_role()
def add_address( def add_address(
ifc: tool.Ifc, parent: ifcopenshell.entity_instance, ifc_class: ADDRESS_TYPE = "IfcPostalAddress" ifc: type[tool.Ifc], parent: ifcopenshell.entity_instance, ifc_class: ADDRESS_TYPE = "IfcPostalAddress"
) -> ifcopenshell.entity_instance: ) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_address", assigned_object=parent, ifc_class=ifc_class) return ifc.run("owner.add_address", assigned_object=parent, ifc_class=ifc_class)
def remove_address(ifc: tool.Ifc, address: ifcopenshell.entity_instance) -> None: def remove_address(ifc: type[tool.Ifc], address: ifcopenshell.entity_instance) -> None:
ifc.run("owner.remove_address", address=address) ifc.run("owner.remove_address", address=address)
def enable_editing_address(owner: tool.Owner, address: ifcopenshell.entity_instance) -> None: def enable_editing_address(owner: type[tool.Owner], address: ifcopenshell.entity_instance) -> None:
owner.set_address(address) owner.set_address(address)
owner.import_address_attributes() owner.import_address_attributes()
def disable_editing_address(owner: tool.Owner) -> None: def disable_editing_address(owner: type[tool.Owner]) -> None:
owner.clear_address() owner.clear_address()
def edit_address(ifc: tool.Ifc, owner: tool.Owner) -> None: def edit_address(ifc: type[tool.Ifc], owner: type[tool.Owner]) -> None:
address = owner.get_address() address = owner.get_address()
ifc.run("owner.edit_address", address=address, attributes=owner.export_address_attributes()) ifc.run("owner.edit_address", address=address, attributes=owner.export_address_attributes())
owner.clear_address() owner.clear_address()
def add_address_attribute(owner: tool.Owner, name: str) -> None: def add_address_attribute(owner: type[tool.Owner], name: tool.Owner.AddressAttributeType) -> None:
owner.add_address_attribute(name) owner.add_address_attribute(name)
def remove_address_attribute(owner: tool.Owner, name: str, id: int) -> None: def remove_address_attribute(owner: type[tool.Owner], name: tool.Owner.AddressAttributeType, id: int) -> None:
owner.remove_address_attribute(name, id) owner.remove_address_attribute(name, id)
def add_organisation(ifc: tool.Ifc) -> ifcopenshell.entity_instance: def add_organisation(ifc: type[tool.Ifc]) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_organisation") return ifc.run("owner.add_organisation")
def remove_organisation(ifc: tool.Ifc, organisation: ifcopenshell.entity_instance) -> None: def remove_organisation(ifc: type[tool.Ifc], organisation: ifcopenshell.entity_instance) -> None:
ifc.run("owner.remove_organisation", organisation=organisation) ifc.run("owner.remove_organisation", organisation=organisation)
def enable_editing_organisation(owner: tool.Owner, organisation: ifcopenshell.entity_instance) -> None: def enable_editing_organisation(owner: type[tool.Owner], organisation: ifcopenshell.entity_instance) -> None:
owner.set_organisation(organisation) owner.set_organisation(organisation)
owner.import_organisation_attributes() owner.import_organisation_attributes()
def disable_editing_organisation(owner: tool.Owner) -> None: def disable_editing_organisation(owner: type[tool.Owner]) -> None:
owner.clear_organisation() owner.clear_organisation()
def edit_organisation(ifc: tool.Ifc, owner: tool.Owner) -> None: def edit_organisation(ifc: type[tool.Ifc], owner: type[tool.Owner]) -> None:
organisation = owner.get_organisation() organisation = owner.get_organisation()
ifc.run("owner.edit_organisation", organisation=organisation, attributes=owner.export_organisation_attributes()) ifc.run("owner.edit_organisation", organisation=organisation, attributes=owner.export_organisation_attributes())
owner.clear_organisation() owner.clear_organisation()
def add_person_and_organisation( def add_person_and_organisation(
ifc: tool.Ifc, person: ifcopenshell.entity_instance, organisation: ifcopenshell.entity_instance ifc: type[tool.Ifc], person: ifcopenshell.entity_instance, organisation: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance: ) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_person_and_organisation", person=person, organisation=organisation) return ifc.run("owner.add_person_and_organisation", person=person, organisation=organisation)
def remove_person_and_organisation( def remove_person_and_organisation(
ifc: tool.Ifc, owner: tool.Owner, person_and_organisation: ifcopenshell.entity_instance ifc: type[tool.Ifc], owner: type[tool.Owner], person_and_organisation: ifcopenshell.entity_instance
) -> None: ) -> None:
if owner.get_user() == person_and_organisation: if owner.get_user() == person_and_organisation:
owner.clear_user() owner.clear_user()
ifc.run("owner.remove_person_and_organisation", person_and_organisation=person_and_organisation) ifc.run("owner.remove_person_and_organisation", person_and_organisation=person_and_organisation)
def set_user(owner: tool.Owner, user: ifcopenshell.entity_instance) -> None: def set_user(owner: type[tool.Owner], user: ifcopenshell.entity_instance) -> None:
owner.set_user(user) owner.set_user(user)
def get_user(owner: tool.Owner) -> Union[ifcopenshell.entity_instance, None]: def get_user(owner: type[tool.Owner]) -> Union[ifcopenshell.entity_instance, None]:
return owner.get_user() return owner.get_user()
def clear_user(owner: tool.Owner) -> None: def clear_user(owner: type[tool.Owner]) -> None:
owner.clear_user() owner.clear_user()
def add_actor( def add_actor(
ifc: tool.Ifc, ifc_class: ACTOR_TYPE, actor: ifcopenshell.entity_instance ifc: type[tool.Ifc], ifc_class: ACTOR_TYPE, actor: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance: ) -> ifcopenshell.entity_instance:
return ifc.run("owner.add_actor", ifc_class=ifc_class, actor=actor) return ifc.run("owner.add_actor", ifc_class=ifc_class, actor=actor)
def remove_actor(ifc: tool.Ifc, actor: ifcopenshell.entity_instance) -> None: def remove_actor(ifc: type[tool.Ifc], actor: ifcopenshell.entity_instance) -> None:
ifc.run("owner.remove_actor", actor=actor) ifc.run("owner.remove_actor", actor=actor)
def enable_editing_actor(owner: tool.Owner, actor: ifcopenshell.entity_instance) -> None: def enable_editing_actor(owner: type[tool.Owner], actor: ifcopenshell.entity_instance) -> None:
owner.set_actor(actor) owner.set_actor(actor)
owner.import_actor_attributes(actor) owner.import_actor_attributes(actor)
def disable_editing_actor(owner: tool.Owner) -> None: def disable_editing_actor(owner: type[tool.Owner]) -> None:
owner.clear_actor() owner.clear_actor()
def edit_actor(ifc: tool.Ifc, owner: tool.Owner) -> None: def edit_actor(ifc: type[tool.Ifc], owner: type[tool.Owner]) -> None:
ifc.run("owner.edit_actor", actor=owner.get_actor(), attributes=owner.export_actor_attributes()) ifc.run("owner.edit_actor", actor=owner.get_actor(), attributes=owner.export_actor_attributes())
disable_editing_actor(owner) disable_editing_actor(owner)
def assign_actor(ifc: tool.Ifc, actor: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance) -> None: def assign_actor(
ifc: type[tool.Ifc], actor: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
) -> None:
ifc.run("owner.assign_actor", relating_actor=actor, related_object=element) ifc.run("owner.assign_actor", relating_actor=actor, related_object=element)
def unassign_actor(ifc: tool.Ifc, actor: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance) -> None: def unassign_actor(
ifc: type[tool.Ifc], actor: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
) -> None:
ifc.run("owner.unassign_actor", relating_actor=actor, related_object=element) ifc.run("owner.unassign_actor", relating_actor=actor, related_object=element)
+2 -1
View File
@@ -71,7 +71,7 @@ class Blender(bonsai.core.tool.Blender):
OBJECT_TYPES_THAT_SUPPORT_EDIT_GPENCIL_MODE = ("GPENCIL",) OBJECT_TYPES_THAT_SUPPORT_EDIT_GPENCIL_MODE = ("GPENCIL",)
TYPE_MANAGER_ICON = "LIGHTPROBE_VOLUME" TYPE_MANAGER_ICON = "LIGHTPROBE_VOLUME"
BLENDER_ENUM_ITEM = Union[tuple[str, str, str], tuple[str, str, str, str], tuple[str, str, str, str, str]] BLENDER_ENUM_ITEM = Union[tuple[str, str, str], tuple[str, str, str, int], tuple[str, str, str, str, int]]
""" """
Options: Options:
@@ -81,6 +81,7 @@ class Blender(bonsai.core.tool.Blender):
- (identifier, name, description, icon, number) - (identifier, name, description, icon, number)
""" """
BLENDER_ENUM_ITEMS = list[BLENDER_ENUM_ITEM]
@classmethod @classmethod
def activate_camera(cls, obj: bpy.types.Object) -> None: def activate_camera(cls, obj: bpy.types.Object) -> None:
+22 -9
View File
@@ -16,22 +16,33 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# 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
import bpy import bpy
import bonsai.bim.helper import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.tool import bonsai.core.tool
import ifcopenshell import ifcopenshell
from typing import Any, Union from typing import Any, Union, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
from bonsai.bim.module.context.prop import BIMContextProperties
class Context(bonsai.core.tool.Context): class Context(bonsai.core.tool.Context):
@classmethod
def get_context_props(cls) -> BIMContextProperties:
assert bpy.context.scene
return bpy.context.scene.BIMContextProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def set_context(cls, context: ifcopenshell.entity_instance) -> None: def set_context(cls, context: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMContextProperties.active_context_id = context.id() props = cls.get_context_props()
props.active_context_id = context.id()
@classmethod @classmethod
def import_attributes(cls) -> None: def import_attributes(cls) -> None:
props = bpy.context.scene.BIMContextProperties props = cls.get_context_props()
props.context_attributes.clear() props.context_attributes.clear()
context = cls.get_context() context = cls.get_context()
@@ -52,20 +63,22 @@ class Context(bonsai.core.tool.Context):
@classmethod @classmethod
def clear_context(cls) -> None: def clear_context(cls) -> None:
bpy.context.scene.BIMContextProperties.active_context_id = 0 props = cls.get_context_props()
props.active_context_id = 0
@classmethod @classmethod
def get_context(cls) -> ifcopenshell.entity_instance: def get_context(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_id(bpy.context.scene.BIMContextProperties.active_context_id) props = cls.get_context_props()
return tool.Ifc.get().by_id(props.active_context_id)
@classmethod @classmethod
def export_attributes(cls) -> dict[str, Any]: def export_attributes(cls) -> dict[str, Any]:
def callback(attributes, blender_attribute) -> bool: props = cls.get_context_props()
def callback(attributes: dict[str, Any], blender_attribute: Attribute) -> bool:
if blender_attribute.name == "Precision": if blender_attribute.name == "Precision":
attributes["Precision"] = float(blender_attribute.get_value()) attributes["Precision"] = float(blender_attribute.get_value())
return True return True
return False return False
return bonsai.bim.helper.export_attributes( return bonsai.bim.helper.export_attributes(props.context_attributes, callback=callback)
bpy.context.scene.BIMContextProperties.context_attributes, callback=callback
)
+20 -8
View File
@@ -61,6 +61,7 @@ if TYPE_CHECKING:
BIMAnnotationProperties, BIMAnnotationProperties,
BIMTextProperties, BIMTextProperties,
BIMCameraProperties, BIMCameraProperties,
BIMAssignedProductProperties,
) )
from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties
@@ -105,15 +106,17 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def get_document_props(cls) -> DocProperties: def get_document_props(cls) -> DocProperties:
return bpy.context.scene.DocProperties assert (scene := bpy.context.scene)
return scene.DocProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def get_annotation_props(cls) -> BIMAnnotationProperties: def get_annotation_props(cls) -> BIMAnnotationProperties:
return bpy.context.scene.BIMAnnotationProperties assert (scene := bpy.context.scene)
return scene.BIMAnnotationProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def get_text_props(cls, obj: bpy.types.Object) -> BIMTextProperties: def get_text_props(cls, obj: bpy.types.Object) -> BIMTextProperties:
return obj.BIMTextProperties return obj.BIMTextProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def get_camera_props(cls, camera: Union[bpy.types.Object, bpy.types.Camera]) -> BIMCameraProperties: def get_camera_props(cls, camera: Union[bpy.types.Object, bpy.types.Camera]) -> BIMCameraProperties:
@@ -124,7 +127,11 @@ class Drawing(bonsai.core.tool.Drawing):
data = camera data = camera
else: else:
assert isinstance(data := camera.data, bpy.types.Camera) assert isinstance(data := camera.data, bpy.types.Camera)
return data.BIMCameraProperties return data.BIMCameraProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def get_object_assigned_product_props(cls, obj: bpy.types.Object) -> BIMAssignedProductProperties:
return obj.BIMAssignedProductProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def canonicalise_class_name(cls, name: str) -> str: def canonicalise_class_name(cls, name: str) -> str:
@@ -406,7 +413,8 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def disable_editing_assigned_product(cls, obj: bpy.types.Object) -> None: def disable_editing_assigned_product(cls, obj: bpy.types.Object) -> None:
obj.BIMAssignedProductProperties.is_editing_product = False props = cls.get_object_assigned_product_props(obj)
props.is_editing_product = False
@classmethod @classmethod
def enable_editing(cls, obj: bpy.types.Object) -> None: def enable_editing(cls, obj: bpy.types.Object) -> None:
@@ -447,7 +455,8 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def enable_editing_assigned_product(cls, obj: bpy.types.Object) -> None: def enable_editing_assigned_product(cls, obj: bpy.types.Object) -> None:
obj.BIMAssignedProductProperties.is_editing_product = True props = cls.get_object_assigned_product_props(obj)
props.is_editing_product = True
@classmethod @classmethod
def ensure_unique_drawing_name(cls, name: str) -> str: def ensure_unique_drawing_name(cls, name: str) -> str:
@@ -1045,11 +1054,14 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def import_assigned_product(cls, obj: bpy.types.Object) -> None: def import_assigned_product(cls, obj: bpy.types.Object) -> None:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
product = cls.get_assigned_product(element) product = cls.get_assigned_product(element)
props = cls.get_object_assigned_product_props(obj)
if product: if product:
obj.BIMAssignedProductProperties.relating_product = tool.Ifc.get_object(product) assert isinstance(product_obj := tool.Ifc.get_object(product), bpy.types.Object)
props.relating_product = product_obj
else: else:
obj.BIMAssignedProductProperties.relating_product = None props.relating_product = None
@classmethod @classmethod
def open_with_user_command(cls, user_command: str, path: str) -> None: def open_with_user_command(cls, user_command: str, path: str) -> None:
+1 -1
View File
@@ -1030,7 +1030,7 @@ class Geometry(bonsai.core.tool.Geometry):
return item.is_a("IfcSweptAreaSolid") or item.is_a("IfcHalfSpaceSolid") return item.is_a("IfcSweptAreaSolid") or item.is_a("IfcHalfSpaceSolid")
@classmethod @classmethod
def is_profile_based(cls, data: bpy.types.Mesh) -> bool: def is_profile_based(cls, data: TYPES_WITH_MESH_PROPERTIES) -> bool:
props = tool.Geometry.get_mesh_props(data) props = tool.Geometry.get_mesh_props(data)
return props.subshape_type == "PROFILE" return props.subshape_type == "PROFILE"
+91 -46
View File
@@ -16,23 +16,35 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# 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
import bpy import bpy
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.helper import bonsai.bim.helper
import ifcopenshell import ifcopenshell
from typing import Union, Any from typing import Union, Any, TYPE_CHECKING, Literal
from typing_extensions import assert_never
if TYPE_CHECKING:
from bonsai.bim.module.owner.prop import BIMOwnerProperties
class Owner(bonsai.core.tool.Owner): class Owner(bonsai.core.tool.Owner):
@classmethod
def get_owner_props(cls) -> BIMOwnerProperties:
return bpy.context.scene.BIMOwnerProperties
@classmethod @classmethod
def set_user(cls, user: ifcopenshell.entity_instance) -> None: def set_user(cls, user: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_user_id = user.id() props = cls.get_owner_props()
props.active_user_id = user.id()
@classmethod @classmethod
def get_user(cls) -> Union[ifcopenshell.entity_instance, None]: def get_user(cls) -> Union[ifcopenshell.entity_instance, None]:
if bpy.context.scene.BIMOwnerProperties.active_user_id: props = cls.get_owner_props()
return tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_user_id) active_user_id = props.active_user_id
if active_user_id:
return tool.Ifc.get().by_id(active_user_id)
elif tool.Ifc.get_schema() == "IFC2X3": elif tool.Ifc.get_schema() == "IFC2X3":
users = tool.Ifc.get().by_type("IfcPersonAndOrganization") users = tool.Ifc.get().by_type("IfcPersonAndOrganization")
if users: if users:
@@ -40,15 +52,17 @@ class Owner(bonsai.core.tool.Owner):
@classmethod @classmethod
def clear_user(cls) -> None: def clear_user(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_user_id = 0 props = cls.get_owner_props()
props.active_user_id = 0
@classmethod @classmethod
def set_address(cls, address: ifcopenshell.entity_instance) -> None: def set_address(cls, address: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_address_id = address.id() props = cls.get_owner_props()
props.active_address_id = address.id()
@classmethod @classmethod
def import_address_attributes(cls) -> None: def import_address_attributes(cls) -> None:
props = bpy.context.scene.BIMOwnerProperties props = props = cls.get_owner_props()
props.address_attributes.clear() props.address_attributes.clear()
props.address_lines.clear() props.address_lines.clear()
props.telephone_numbers.clear() props.telephone_numbers.clear()
@@ -58,7 +72,7 @@ class Owner(bonsai.core.tool.Owner):
address = cls.get_address() address = cls.get_address()
def callback(name, prop, data): def callback(name: str, prop, data: dict[str, Any]) -> None:
if name == "AddressLines": if name == "AddressLines":
for line in data[name] or []: for line in data[name] or []:
props.address_lines.add().name = line props.address_lines.add().name = line
@@ -79,15 +93,17 @@ class Owner(bonsai.core.tool.Owner):
@classmethod @classmethod
def clear_address(cls) -> None: def clear_address(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_address_id = 0 props = cls.get_owner_props()
props.active_address_id = 0
@classmethod @classmethod
def get_address(cls) -> ifcopenshell.entity_instance: def get_address(cls) -> ifcopenshell.entity_instance:
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_address_id) props = cls.get_owner_props()
return tool.Ifc().get().by_id(props.active_address_id)
@classmethod @classmethod
def export_address_attributes(cls) -> dict[str, Any]: def export_address_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
attributes = bonsai.bim.helper.export_attributes(props.address_attributes) attributes = bonsai.bim.helper.export_attributes(props.address_attributes)
if cls.get_address().is_a("IfcPostalAddress"): if cls.get_address().is_a("IfcPostalAddress"):
attributes["AddressLines"] = [l.name for l in props.address_lines] or None attributes["AddressLines"] = [l.name for l in props.address_lines] or None
@@ -98,9 +114,13 @@ class Owner(bonsai.core.tool.Owner):
attributes["MessagingIDs"] = [l.name for l in props.messaging_ids] or None attributes["MessagingIDs"] = [l.name for l in props.messaging_ids] or None
return attributes return attributes
AddressAttributeType = Literal[
"AddressLines", "TelephoneNumbers", "FacsimileNumbers", "ElectronicMailAddresses", "MessagingIDs"
]
@classmethod @classmethod
def add_address_attribute(cls, name: str) -> None: def add_address_attribute(cls, name: AddressAttributeType) -> None:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
if name == "AddressLines": if name == "AddressLines":
props.address_lines.add() props.address_lines.add()
elif name == "TelephoneNumbers": elif name == "TelephoneNumbers":
@@ -111,10 +131,12 @@ class Owner(bonsai.core.tool.Owner):
props.electronic_mail_addresses.add() props.electronic_mail_addresses.add()
elif name == "MessagingIDs": elif name == "MessagingIDs":
props.messaging_ids.add() props.messaging_ids.add()
else:
assert_never(name)
@classmethod @classmethod
def remove_address_attribute(cls, name: str, id: int) -> None: def remove_address_attribute(cls, name: AddressAttributeType, id: int) -> None:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
if name == "AddressLines": if name == "AddressLines":
props.address_lines.remove(id) props.address_lines.remove(id)
elif name == "TelephoneNumbers": elif name == "TelephoneNumbers":
@@ -125,47 +147,53 @@ class Owner(bonsai.core.tool.Owner):
props.electronic_mail_addresses.remove(id) props.electronic_mail_addresses.remove(id)
elif name == "MessagingIDs": elif name == "MessagingIDs":
props.messaging_ids.remove(id) props.messaging_ids.remove(id)
else:
assert_never(name)
@classmethod @classmethod
def set_organisation(cls, organisation: ifcopenshell.entity_instance) -> None: def set_organisation(cls, organisation: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_organisation_id = organisation.id() props = cls.get_owner_props()
props.active_organisation_id = organisation.id()
@classmethod @classmethod
def import_organisation_attributes(cls) -> None: def import_organisation_attributes(cls) -> None:
organisation = tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_organisation_id) props = cls.get_owner_props()
props = bpy.context.scene.BIMOwnerProperties organisation = tool.Ifc.get().by_id(props.active_organisation_id)
props.organisation_attributes.clear() props.organisation_attributes.clear()
bonsai.bim.helper.import_attributes("IfcOrganization", props.organisation_attributes, organisation.get_info()) bonsai.bim.helper.import_attributes("IfcOrganization", props.organisation_attributes, organisation.get_info())
@classmethod @classmethod
def clear_organisation(cls) -> None: def clear_organisation(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_organisation_id = 0 props = cls.get_owner_props()
props.active_organisation_id = 0
@classmethod @classmethod
def export_organisation_attributes(cls) -> dict[str, Any]: def export_organisation_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
attributes = bonsai.bim.helper.export_attributes(props.organisation_attributes) attributes = bonsai.bim.helper.export_attributes(props.organisation_attributes)
return attributes return attributes
@classmethod @classmethod
def get_organisation(cls) -> ifcopenshell.entity_instance: def get_organisation(cls) -> ifcopenshell.entity_instance:
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_organisation_id) props = cls.get_owner_props()
return tool.Ifc().get().by_id(props.active_organisation_id)
@classmethod @classmethod
def set_person(cls, person: ifcopenshell.entity_instance) -> None: def set_person(cls, person: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_person_id = person.id() props = cls.get_owner_props()
props.active_person_id = person.id()
@classmethod @classmethod
def import_person_attributes(cls) -> None: def import_person_attributes(cls) -> None:
person = tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_person_id) props = cls.get_owner_props()
props = bpy.context.scene.BIMOwnerProperties person = tool.Ifc.get().by_id(props.active_person_id)
props.person_attributes.clear() props.person_attributes.clear()
props.middle_names.clear() props.middle_names.clear()
props.prefix_titles.clear() props.prefix_titles.clear()
props.suffix_titles.clear() props.suffix_titles.clear()
def callback(name, prop, data): def callback(name: str, prop, data: dict[str, Any]) -> None:
if name == "MiddleNames": if name == "MiddleNames":
for name in data["MiddleNames"] or []: for name in data["MiddleNames"] or []:
props.middle_names.add().name = name or "" props.middle_names.add().name = name or ""
@@ -180,11 +208,12 @@ class Owner(bonsai.core.tool.Owner):
@classmethod @classmethod
def clear_person(cls) -> None: def clear_person(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_person_id = 0 props = cls.get_owner_props()
props.active_person_id = 0
@classmethod @classmethod
def export_person_attributes(cls) -> dict[str, Any]: def export_person_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
attributes = bonsai.bim.helper.export_attributes(props.person_attributes) attributes = bonsai.bim.helper.export_attributes(props.person_attributes)
attributes["MiddleNames"] = [v.name for v in props.middle_names] if props.middle_names else None attributes["MiddleNames"] = [v.name for v in props.middle_names] if props.middle_names else None
attributes["PrefixTitles"] = [v.name for v in props.prefix_titles] if props.prefix_titles else None attributes["PrefixTitles"] = [v.name for v in props.prefix_titles] if props.prefix_titles else None
@@ -193,69 +222,85 @@ class Owner(bonsai.core.tool.Owner):
@classmethod @classmethod
def get_person(cls) -> ifcopenshell.entity_instance: def get_person(cls) -> ifcopenshell.entity_instance:
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_person_id) props = cls.get_owner_props()
return tool.Ifc().get().by_id(props.active_person_id)
PersonAttributeType = Literal["MiddleNames", "PrefixTitles", "SuffixTitles"]
@classmethod @classmethod
def add_person_attribute(cls, name: str) -> None: def add_person_attribute(cls, name: PersonAttributeType) -> None:
props = cls.get_owner_props()
if name == "MiddleNames": if name == "MiddleNames":
bpy.context.scene.BIMOwnerProperties.middle_names.add() props.middle_names.add()
elif name == "PrefixTitles": elif name == "PrefixTitles":
bpy.context.scene.BIMOwnerProperties.prefix_titles.add() props.prefix_titles.add()
elif name == "SuffixTitles": elif name == "SuffixTitles":
bpy.context.scene.BIMOwnerProperties.suffix_titles.add() props.suffix_titles.add()
else:
assert_never(name)
@classmethod @classmethod
def remove_person_attribute(cls, name: str, id: int) -> None: def remove_person_attribute(cls, name: PersonAttributeType, id: int) -> None:
props = cls.get_owner_props()
if name == "MiddleNames": if name == "MiddleNames":
bpy.context.scene.BIMOwnerProperties.middle_names.remove(id) props.middle_names.remove(id)
elif name == "PrefixTitles": elif name == "PrefixTitles":
bpy.context.scene.BIMOwnerProperties.prefix_titles.remove(id) props.prefix_titles.remove(id)
elif name == "SuffixTitles": elif name == "SuffixTitles":
bpy.context.scene.BIMOwnerProperties.suffix_titles.remove(id) props.suffix_titles.remove(id)
else:
assert_never(name)
@classmethod @classmethod
def set_role(cls, role: ifcopenshell.entity_instance) -> None: def set_role(cls, role: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_role_id = role.id() props = cls.get_owner_props()
props.active_role_id = role.id()
@classmethod @classmethod
def import_role_attributes(cls) -> None: def import_role_attributes(cls) -> None:
role = cls.get_role() role = cls.get_role()
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
props.role_attributes.clear() props.role_attributes.clear()
bonsai.bim.helper.import_attributes("IfcActorRole", props.role_attributes, role.get_info()) bonsai.bim.helper.import_attributes("IfcActorRole", props.role_attributes, role.get_info())
@classmethod @classmethod
def clear_role(cls) -> None: def clear_role(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_role_id = 0 props = cls.get_owner_props()
props.active_role_id = 0
@classmethod @classmethod
def get_role(cls) -> ifcopenshell.entity_instance: def get_role(cls) -> ifcopenshell.entity_instance:
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_role_id) props = cls.get_owner_props()
return tool.Ifc().get().by_id(props.active_role_id)
@classmethod @classmethod
def export_role_attributes(cls) -> dict[str, Any]: def export_role_attributes(cls) -> dict[str, Any]:
return bonsai.bim.helper.export_attributes(bpy.context.scene.BIMOwnerProperties.role_attributes) props = cls.get_owner_props()
return bonsai.bim.helper.export_attributes(props.role_attributes)
@classmethod @classmethod
def set_actor(cls, actor: ifcopenshell.entity_instance) -> None: def set_actor(cls, actor: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMOwnerProperties.active_actor_id = actor.id() props = cls.get_owner_props()
props.active_actor_id = actor.id()
@classmethod @classmethod
def import_actor_attributes(cls, actor: ifcopenshell.entity_instance) -> None: def import_actor_attributes(cls, actor: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
props.actor_attributes.clear() props.actor_attributes.clear()
bonsai.bim.helper.import_attributes2(actor, props.actor_attributes) bonsai.bim.helper.import_attributes2(actor, props.actor_attributes)
@classmethod @classmethod
def clear_actor(cls) -> None: def clear_actor(cls) -> None:
bpy.context.scene.BIMOwnerProperties.active_actor_id = 0 props = cls.get_owner_props()
props.active_actor_id = 0
@classmethod @classmethod
def export_actor_attributes(cls) -> dict[str, Any]: def export_actor_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMOwnerProperties props = cls.get_owner_props()
attributes = bonsai.bim.helper.export_attributes(props.actor_attributes) attributes = bonsai.bim.helper.export_attributes(props.actor_attributes)
return attributes return attributes
@classmethod @classmethod
def get_actor(cls) -> ifcopenshell.entity_instance: def get_actor(cls) -> ifcopenshell.entity_instance:
return tool.Ifc().get().by_id(bpy.context.scene.BIMOwnerProperties.active_actor_id) props = cls.get_owner_props()
return tool.Ifc().get().by_id(props.active_actor_id)
+1 -1
View File
@@ -339,7 +339,7 @@ class Sequence(bonsai.core.tool.Sequence):
@classmethod @classmethod
def get_task_attribute_value(cls, attribute_name: str) -> Any: def get_task_attribute_value(cls, attribute_name: str) -> Any:
props = cls.get_work_schedule_props() props = cls.get_work_schedule_props()
return props.task_attributes.get(attribute_name).get_value() return props.task_attributes[attribute_name].get_value()
@classmethod @classmethod
def get_active_task(cls) -> ifcopenshell.entity_instance: def get_active_task(cls) -> ifcopenshell.entity_instance:
+6 -1
View File
@@ -22,8 +22,12 @@ import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import pytest import pytest
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
from typing import TYPE_CHECKING
from bonsai.tool.blender import Blender as subject from bonsai.tool.blender import Blender as subject
if TYPE_CHECKING:
import bpy._typing.rna_enums as rna_enums
class TestImplementsTool(NewFile): class TestImplementsTool(NewFile):
def test_run(self): def test_run(self):
@@ -34,6 +38,7 @@ class TestCopyNodeGraph(NewFile):
def test_run(self): def test_run(self):
material_to = bpy.data.materials.new("material_to") material_to = bpy.data.materials.new("material_to")
material_to.use_nodes = True material_to.use_nodes = True
assert material_to.node_tree
material_to_nodes = material_to.node_tree.nodes material_to_nodes = material_to.node_tree.nodes
assert len(material_to_nodes) == 2 assert len(material_to_nodes) == 2
for node in material_to_nodes: for node in material_to_nodes:
@@ -70,7 +75,7 @@ class TestBlenderErrorMessageExtraction(NewFile):
bl_idname = "object.test_fail_operator" bl_idname = "object.test_fail_operator"
bl_label = "Test Fail Operator" bl_label = "Test Fail Operator"
def execute(self, context): def execute(self, context) -> "set[rna_enums.OperatorReturnItems]":
self.report({"INFO"}, "Info message.") self.report({"INFO"}, "Info message.")
subject.report_operator_errors(self, ERROR_REPORTS) subject.report_operator_errors(self, ERROR_REPORTS)
return {"FINISHED"} return {"FINISHED"}
+6 -4
View File
@@ -138,6 +138,7 @@ class TestAddBrickifcProject(NewFile):
class TestAddBrickifcReference(NewFile): class TestAddBrickifcReference(NewFile):
def test_run(self): def test_run(self):
TestAddBrickifcProject().test_run() TestAddBrickifcProject().test_run()
assert BrickStore.graph
element = tool.Ifc.get().createIfcChiller(ifcopenshell.guid.new()) element = tool.Ifc.get().createIfcChiller(ifcopenshell.guid.new())
element.Name = "Chiller" element.Name = "Chiller"
project = URIRef(f"http://example.org/digitaltwin#{tool.Ifc.get().by_type('IfcProject')[0].GlobalId}") project = URIRef(f"http://example.org/digitaltwin#{tool.Ifc.get().by_type('IfcProject')[0].GlobalId}")
@@ -173,6 +174,7 @@ class TestAddRelation(NewFile):
class TestRemoveRelation(NewFile): class TestRemoveRelation(NewFile):
def test_run(self): def test_run(self):
TestAddRelation().test_run() TestAddRelation().test_run()
assert BrickStore.graph
source, relation, destination = list( source, relation, destination = list(
BrickStore.graph.triples((None, URIRef("https://brickschema.org/schema/Brick#feeds"), None)) BrickStore.graph.triples((None, URIRef("https://brickschema.org/schema/Brick#feeds"), None))
)[0] )[0]
@@ -321,7 +323,7 @@ class TestGetConvertableBrickSystems(NewFile):
class TestGetParentSpace(NewFile): class TestGetParentSpace(NewFile):
def test_run(cls): def test_run(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBuildingStorey") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBuildingStorey")
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSpace") subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSpace")
@@ -333,17 +335,17 @@ class TestGetParentSpace(NewFile):
class TestGetElementContainer(NewFile): class TestGetElementContainer(NewFile):
def test_nothing(cls): def test_nothing(self):
pass pass
class TestGetElementSystems(NewFile): class TestGetElementSystems(NewFile):
def test_nothing(cls): def test_nothing(self):
pass pass
class TestGetElementFeeds(NewFile): class TestGetElementFeeds(NewFile):
def test_run(cls): def test_run(self):
pass pass
+25 -8
View File
@@ -20,6 +20,9 @@ import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.api.aggregate import ifcopenshell.api.aggregate
import ifcopenshell.api.feature
import ifcopenshell.api.group
import ifcopenshell.api.spatial
import ifcopenshell.util.element import ifcopenshell.util.element
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
@@ -34,6 +37,7 @@ class TestImplementsTool(NewFile):
class TestAssign(NewIfc): class TestAssign(NewIfc):
def test_walls_are_placed_in_its_spatial_collection(self): def test_walls_are_placed_in_its_spatial_collection(self):
assert bpy.context.scene
wall_obj = bpy.data.objects.new("Object", None) wall_obj = bpy.data.objects.new("Object", None)
wall_element = tool.Ifc.get().createIfcWall() wall_element = tool.Ifc.get().createIfcWall()
tool.Ifc.link(wall_element, wall_obj) tool.Ifc.link(wall_element, wall_obj)
@@ -48,6 +52,7 @@ class TestAssign(NewIfc):
assert "IfcSite" in wall_obj.users_collection[0].name assert "IfcSite" in wall_obj.users_collection[0].name
def test_walls_are_unsorted_if_not_decomposes(self): def test_walls_are_unsorted_if_not_decomposes(self):
assert bpy.context.scene
wall_obj = bpy.data.objects.new("Object", None) wall_obj = bpy.data.objects.new("Object", None)
wall_element = tool.Ifc.get().createIfcWall() wall_element = tool.Ifc.get().createIfcWall()
tool.Ifc.link(wall_element, wall_obj) tool.Ifc.link(wall_element, wall_obj)
@@ -57,6 +62,7 @@ class TestAssign(NewIfc):
assert "Unsorted" in wall_obj.users_collection[0].name assert "Unsorted" in wall_obj.users_collection[0].name
def test_spatial_structure_elements_are_placed_in_a_collection_of_the_same_name(self): def test_spatial_structure_elements_are_placed_in_a_collection_of_the_same_name(self):
assert bpy.context.scene
building_obj = bpy.data.objects.new("IfcBuilding/Name", None) building_obj = bpy.data.objects.new("IfcBuilding/Name", None)
building_element = tool.Ifc.get().createIfcBuilding() building_element = tool.Ifc.get().createIfcBuilding()
tool.Ifc.link(building_element, building_obj) tool.Ifc.link(building_element, building_obj)
@@ -71,6 +77,7 @@ class TestAssign(NewIfc):
assert building_obj.users_collection[0].name == building_obj.name assert building_obj.users_collection[0].name == building_obj.name
def test_spaces_are_special_and_are_placed_in_a_spaces_collection(self): def test_spaces_are_special_and_are_placed_in_a_spaces_collection(self):
assert bpy.context.scene
space_obj = bpy.data.objects.new("IfcSpace/Name", None) space_obj = bpy.data.objects.new("IfcSpace/Name", None)
space_element = tool.Ifc.get().createIfcSpace() space_element = tool.Ifc.get().createIfcSpace()
tool.Ifc.link(space_element, space_obj) tool.Ifc.link(space_element, space_obj)
@@ -85,6 +92,7 @@ class TestAssign(NewIfc):
assert space_obj.users_collection[0].name == "IfcSpace" assert space_obj.users_collection[0].name == "IfcSpace"
def test_multiple_assigns_do_not_create_duplicate_spatial_structure_collections(self): def test_multiple_assigns_do_not_create_duplicate_spatial_structure_collections(self):
assert bpy.context.scene
space_obj = bpy.data.objects.new("IfcSpace/Name", None) space_obj = bpy.data.objects.new("IfcSpace/Name", None)
space_element = tool.Ifc.get().createIfcSpace() space_element = tool.Ifc.get().createIfcSpace()
tool.Ifc.link(space_element, space_obj) tool.Ifc.link(space_element, space_obj)
@@ -102,6 +110,7 @@ class TestAssign(NewIfc):
assert not bpy.data.collections.get("IfcSite/My Site.001") assert not bpy.data.collections.get("IfcSite/My Site.001")
def test_spatial_zone_elements_are_not_placed_in_a_collection_of_the_same_name(self): def test_spatial_zone_elements_are_not_placed_in_a_collection_of_the_same_name(self):
assert bpy.context.scene
space_obj = bpy.data.objects.new("IfcSpaceZone/Name", None) space_obj = bpy.data.objects.new("IfcSpaceZone/Name", None)
space_element = tool.Ifc.get().createIfcSpatialZone() space_element = tool.Ifc.get().createIfcSpatialZone()
tool.Ifc.link(space_element, space_obj) tool.Ifc.link(space_element, space_obj)
@@ -116,6 +125,7 @@ class TestAssign(NewIfc):
assert space_obj.users_collection[0].name != space_obj.name assert space_obj.users_collection[0].name != space_obj.name
def test_aggregates_are_also_placed_in_their_container(self): def test_aggregates_are_also_placed_in_their_container(self):
assert bpy.context.scene
element_obj = bpy.data.objects.new("IfcElementAssembly/Name", None) element_obj = bpy.data.objects.new("IfcElementAssembly/Name", None)
element = tool.Ifc.get().createIfcElementAssembly() element = tool.Ifc.get().createIfcElementAssembly()
subelement_obj = bpy.data.objects.new("IfcBeam/Name", None) subelement_obj = bpy.data.objects.new("IfcBeam/Name", None)
@@ -142,6 +152,7 @@ class TestAssign(NewIfc):
assert "IfcSite" in subelement_obj.users_collection[0].name assert "IfcSite" in subelement_obj.users_collection[0].name
def test_projects_are_placed_in_a_collection_of_the_same_name(self): def test_projects_are_placed_in_a_collection_of_the_same_name(self):
assert bpy.context.scene
tool.Ifc.set(ifcopenshell.file()) tool.Ifc.set(ifcopenshell.file())
element_obj = bpy.data.objects.new("IfcProject/Name", None) element_obj = bpy.data.objects.new("IfcProject/Name", None)
element = tool.Ifc.get().createIfcProject() element = tool.Ifc.get().createIfcProject()
@@ -152,6 +163,7 @@ class TestAssign(NewIfc):
assert element_obj.users_collection[0].name == element_obj.name assert element_obj.users_collection[0].name == element_obj.name
def test_multiple_assigns_do_not_create_duplicate_collections(self): def test_multiple_assigns_do_not_create_duplicate_collections(self):
assert bpy.context.scene
tool.Ifc.set(ifcopenshell.file()) tool.Ifc.set(ifcopenshell.file())
element_obj = bpy.data.objects.new("IfcProject/Name", None) element_obj = bpy.data.objects.new("IfcProject/Name", None)
element = tool.Ifc.get().createIfcProject() element = tool.Ifc.get().createIfcProject()
@@ -163,6 +175,7 @@ class TestAssign(NewIfc):
assert not bpy.data.collections.get("IfcProject/Name.001") assert not bpy.data.collections.get("IfcProject/Name.001")
def test_own_collections_are_retained_and_name_synced(self): def test_own_collections_are_retained_and_name_synced(self):
assert bpy.context.scene
building_obj = bpy.data.objects.new("IfcBuilding/Name", None) building_obj = bpy.data.objects.new("IfcBuilding/Name", None)
building_element = tool.Ifc.get().createIfcBuilding() building_element = tool.Ifc.get().createIfcBuilding()
tool.Ifc.link(building_element, building_obj) tool.Ifc.link(building_element, building_obj)
@@ -178,22 +191,24 @@ class TestAssign(NewIfc):
) )
subject.assign(building_obj) subject.assign(building_obj)
assert bpy.context.scene.collection.children.find(building_collection.name) != -1 assert bpy.context.scene.collection.children.find(building_collection.name) != -1
assert bpy.data.collections.get("IfcSite/My Site").children.find(building_collection.name) == -1 assert bpy.data.collections["IfcSite/My Site"].children.find(building_collection.name) == -1
assert bpy.data.collections.get("IfcProject/My Project").children.find(building_collection.name) == -1 assert bpy.data.collections["IfcProject/My Project"].children.find(building_collection.name) == -1
assert bpy.context.scene.collection.children.find(building_collection.name) != -1 assert bpy.context.scene.collection.children.find(building_collection.name) != -1
assert building_collection.objects.find(building_obj.name) != -1 assert building_collection.objects.find(building_obj.name) != -1
assert building_collection.name == "IfcBuilding/Name" assert building_collection.name == "IfcBuilding/Name"
def test_types_are_placed_in_the_types_collection(self): def test_types_are_placed_in_the_types_collection(self):
assert bpy.context.scene
element_obj = bpy.data.objects.new("IfcWallType/Name", None) element_obj = bpy.data.objects.new("IfcWallType/Name", None)
element = tool.Ifc.get().createIfcWallType() element = tool.Ifc.get().createIfcWallType()
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
bpy.context.scene.collection.objects.link(element_obj) bpy.context.scene.collection.objects.link(element_obj)
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcTypeProduct" assert element_obj.users_collection[0].name == "IfcTypeProduct"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcTypeProduct") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcTypeProduct")
def test_openings_are_placed_in_their_voided_elements_container(self): def test_openings_are_placed_in_their_voided_elements_container(self):
assert bpy.context.scene
element_obj = bpy.data.objects.new("IfcOpeningElement/Name", None) element_obj = bpy.data.objects.new("IfcOpeningElement/Name", None)
element = tool.Ifc.get().createIfcOpeningElement() element = tool.Ifc.get().createIfcOpeningElement()
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
@@ -210,6 +225,7 @@ class TestAssign(NewIfc):
assert element_obj.users_collection[0].name == "IfcSite/My Site" assert element_obj.users_collection[0].name == "IfcSite/My Site"
def test_grids_are_placed_in_their_container(self): def test_grids_are_placed_in_their_container(self):
assert bpy.context.scene
element_obj = bpy.data.objects.new("IfcGrid/Name", None) element_obj = bpy.data.objects.new("IfcGrid/Name", None)
element = tool.Ifc.get().createIfcGrid() element = tool.Ifc.get().createIfcGrid()
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
@@ -223,6 +239,7 @@ class TestAssign(NewIfc):
assert element_obj.users_collection[0].name == "IfcSite/My Site" assert element_obj.users_collection[0].name == "IfcSite/My Site"
def test_grids_axes_are_placed_in_the_grids_container(self): def test_grids_axes_are_placed_in_the_grids_container(self):
assert bpy.context.scene
element_obj = bpy.data.objects.new("IfcGrid/Name", None) element_obj = bpy.data.objects.new("IfcGrid/Name", None)
axis_obj = bpy.data.objects.new("IfcGrid/Name", None) axis_obj = bpy.data.objects.new("IfcGrid/Name", None)
axis = tool.Ifc.get().createIfcGridAxis() axis = tool.Ifc.get().createIfcGridAxis()
@@ -250,7 +267,7 @@ class TestAssign(NewIfc):
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcAnnotation/DRAWING" assert element_obj.users_collection[0].name == "IfcAnnotation/DRAWING"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcAnnotation/DRAWING") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcAnnotation/DRAWING")
def test_annotations_are_placed_in_their_drawings_collection(self): def test_annotations_are_placed_in_their_drawings_collection(self):
self.test_drawings_are_placed_in_their_own_collection() self.test_drawings_are_placed_in_their_own_collection()
@@ -272,7 +289,7 @@ class TestAssign(NewIfc):
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcStructuralItem" assert element_obj.users_collection[0].name == "IfcStructuralItem"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcStructuralItem") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcStructuralItem")
def test_structural_connections_are_placed_in_a_connections_collection(self): def test_structural_connections_are_placed_in_a_connections_collection(self):
element_obj = bpy.data.objects.new("IfcStructuralCurveConnection/Name", None) element_obj = bpy.data.objects.new("IfcStructuralCurveConnection/Name", None)
@@ -280,7 +297,7 @@ class TestAssign(NewIfc):
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcStructuralItem" assert element_obj.users_collection[0].name == "IfcStructuralItem"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcStructuralItem") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcStructuralItem")
class TestAssignIFC4X3(NewIfc4X3): class TestAssignIFC4X3(NewIfc4X3):
@@ -290,7 +307,7 @@ class TestAssignIFC4X3(NewIfc4X3):
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcLinearPositioningElement" assert element_obj.users_collection[0].name == "IfcLinearPositioningElement"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcLinearPositioningElement") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcLinearPositioningElement")
def test_referents_are_placed_in_a_special_collection(self): def test_referents_are_placed_in_a_special_collection(self):
element_obj = bpy.data.objects.new("Name", None) element_obj = bpy.data.objects.new("Name", None)
@@ -298,4 +315,4 @@ class TestAssignIFC4X3(NewIfc4X3):
tool.Ifc.link(element, element_obj) tool.Ifc.link(element, element_obj)
subject.assign(element_obj) subject.assign(element_obj)
assert element_obj.users_collection[0].name == "IfcReferent" assert element_obj.users_collection[0].name == "IfcReferent"
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcReferent") assert bpy.data.collections["IfcProject/My Project"].children.get("IfcReferent")
+16 -14
View File
@@ -34,7 +34,8 @@ class TestSetContext(test.bim.bootstrap.NewFile):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext() context = ifc.createIfcGeometricRepresentationContext()
subject.set_context(context) subject.set_context(context)
assert bpy.context.scene.BIMContextProperties.active_context_id == context.id() props = subject.get_context_props()
assert props.active_context_id == context.id()
class TestImportAttributes(test.bim.bootstrap.NewFile): class TestImportAttributes(test.bim.bootstrap.NewFile):
@@ -48,11 +49,11 @@ class TestImportAttributes(test.bim.bootstrap.NewFile):
context.Precision = 1 context.Precision = 1
subject.set_context(context) subject.set_context(context)
subject.import_attributes() subject.import_attributes()
props = bpy.context.scene.BIMContextProperties props = subject.get_context_props()
assert props.context_attributes.get("ContextIdentifier").string_value == "ContextIdentifier" assert props.context_attributes["ContextIdentifier"].string_value == "ContextIdentifier"
assert props.context_attributes.get("ContextType").string_value == "ContextType" assert props.context_attributes["ContextType"].string_value == "ContextType"
assert props.context_attributes.get("CoordinateSpaceDimension").int_value == 1 assert props.context_attributes["CoordinateSpaceDimension"].int_value == 1
assert props.context_attributes.get("Precision").string_value == "1.0" assert props.context_attributes["Precision"].string_value == "1.0"
def test_importing_a_subcontext(self): def test_importing_a_subcontext(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -63,11 +64,11 @@ class TestImportAttributes(test.bim.bootstrap.NewFile):
subcontext.UserDefinedTargetView = "UserDefinedTargetView" subcontext.UserDefinedTargetView = "UserDefinedTargetView"
subject.set_context(subcontext) subject.set_context(subcontext)
subject.import_attributes() subject.import_attributes()
props = bpy.context.scene.BIMContextProperties props = subject.get_context_props()
assert props.context_attributes.get("TargetScale").float_value == 0.5 assert props.context_attributes["TargetScale"].float_value == 0.5
assert props.context_attributes.get("TargetView").enum_value == "NOTDEFINED" assert props.context_attributes["TargetView"].enum_value == "NOTDEFINED"
assert props.context_attributes.get("UserDefinedTargetView").string_value == "UserDefinedTargetView" assert props.context_attributes["UserDefinedTargetView"].string_value == "UserDefinedTargetView"
assert not props.context_attributes.get("Precision") assert not props.context_attributes["Precision"]
def test_importing_twice(self): def test_importing_twice(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -78,15 +79,16 @@ class TestImportAttributes(test.bim.bootstrap.NewFile):
subject.import_attributes() subject.import_attributes()
context.ContextIdentifier = "ContextIdentifier2" context.ContextIdentifier = "ContextIdentifier2"
subject.import_attributes() subject.import_attributes()
props = bpy.context.scene.BIMContextProperties props = subject.get_context_props()
assert props.context_attributes.get("ContextIdentifier").string_value == "ContextIdentifier2" assert props.context_attributes["ContextIdentifier"].string_value == "ContextIdentifier2"
class TestClearContext(test.bim.bootstrap.NewFile): class TestClearContext(test.bim.bootstrap.NewFile):
def test_run(self): def test_run(self):
TestSetContext().test_run() TestSetContext().test_run()
subject.clear_context() subject.clear_context()
assert bpy.context.scene.BIMContextProperties.active_context_id == 0 props = subject.get_context_props()
assert props.active_context_id == 0
class TestGetContext(test.bim.bootstrap.NewFile): class TestGetContext(test.bim.bootstrap.NewFile):
+27 -9
View File
@@ -21,6 +21,7 @@ from pathlib import Path
import bpy import bpy
import mathutils import mathutils
import ifcopenshell import ifcopenshell
import ifcopenshell.api.root
import ifcopenshell.guid import ifcopenshell.guid
import ifcopenshell.util.element import ifcopenshell.util.element
import bonsai.core.tool import bonsai.core.tool
@@ -68,7 +69,7 @@ class TestCreateCamera(NewFile):
class TestCreateSvgSheet(NewFile): class TestCreateSvgSheet(NewFile):
def test_run(self): def test_run(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject") ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
ifc_path = Path("test/files/temp/test.ifc").absolute() ifc_path = Path("test/files/temp/test.ifc").absolute()
bpy.ops.bim.save_project(filepath=str(ifc_path), should_save_as=True) bpy.ops.bim.save_project(filepath=str(ifc_path), should_save_as=True)
@@ -92,6 +93,7 @@ class TestDeleteCollection(NewFile):
class TestDeleteDrawingElements(NewFile): class TestDeleteDrawingElements(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh")) obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
@@ -155,13 +157,15 @@ class TestDisableEditingText(NewFile):
class TestDisableEditingAssignedProduct(NewFile): class TestDisableEditingAssignedProduct(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
obj.BIMAssignedProductProperties.is_editing_product = True props = subject.get_object_assigned_product_props(obj)
props.is_editing_product = True
subject.disable_editing_assigned_product(obj) subject.disable_editing_assigned_product(obj)
assert obj.BIMAssignedProductProperties.is_editing_product == False assert props.is_editing_product == False
class TestEnableEditing(NewFile): class TestEnableEditing(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
bpy.context.scene.collection.objects.link(obj) bpy.context.scene.collection.objects.link(obj)
subject.enable_editing(obj) subject.enable_editing(obj)
@@ -211,8 +215,9 @@ class TestEnableEditingText(NewFile):
class TestEnableEditingAssignedProduct(NewFile): class TestEnableEditingAssignedProduct(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
props = subject.get_object_assigned_product_props(obj)
subject.enable_editing_assigned_product(obj) subject.enable_editing_assigned_product(obj)
assert obj.BIMAssignedProductProperties.is_editing_product == True assert props.is_editing_product == True
class TestEnsureUniqueDrawingName(NewFile): class TestEnsureUniqueDrawingName(NewFile):
@@ -314,6 +319,7 @@ class TestGetDocumentUri(NewFile):
class TestGetDrawingCollection(NewFile): class TestGetDrawingCollection(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
@@ -378,6 +384,7 @@ class TestGenerateDrawingMatrix(NewFile):
assert subject.generate_drawing_matrix("PLAN_VIEW", 0) == mathutils.Matrix() assert subject.generate_drawing_matrix("PLAN_VIEW", 0) == mathutils.Matrix()
def test_creating_a_plan_view_at_the_cursor_at_a_storey(self): def test_creating_a_plan_view_at_the_cursor_at_a_storey(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
@@ -397,6 +404,7 @@ class TestGenerateDrawingMatrix(NewFile):
) )
def test_creating_an_rcp_at_the_cursor_at_a_storey(self): def test_creating_an_rcp_at_the_cursor_at_a_storey(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
@@ -410,48 +418,56 @@ class TestGenerateDrawingMatrix(NewFile):
) )
def test_creating_a_north_elevation_at_the_cursor(self): def test_creating_a_north_elevation_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("ELEVATION_VIEW", "NORTH") == mathutils.Matrix( assert subject.generate_drawing_matrix("ELEVATION_VIEW", "NORTH") == mathutils.Matrix(
((-1, 0, 0, 1), (0, 0, 1, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((-1, 0, 0, 1), (0, 0, 1, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_a_south_elevation_at_the_cursor(self): def test_creating_a_south_elevation_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("ELEVATION_VIEW", "SOUTH") == mathutils.Matrix( assert subject.generate_drawing_matrix("ELEVATION_VIEW", "SOUTH") == mathutils.Matrix(
((1, 0, 0, 1), (0, 0, -1, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((1, 0, 0, 1), (0, 0, -1, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_an_east_elevation_at_the_cursor(self): def test_creating_an_east_elevation_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("ELEVATION_VIEW", "EAST") == mathutils.Matrix( assert subject.generate_drawing_matrix("ELEVATION_VIEW", "EAST") == mathutils.Matrix(
((0, 0, 1, 1), (1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((0, 0, 1, 1), (1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_a_west_elevation_at_the_cursor(self): def test_creating_a_west_elevation_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("ELEVATION_VIEW", "WEST") == mathutils.Matrix( assert subject.generate_drawing_matrix("ELEVATION_VIEW", "WEST") == mathutils.Matrix(
((0, 0, -1, 1), (-1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((0, 0, -1, 1), (-1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_a_north_section_at_the_cursor(self): def test_creating_a_north_section_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("SECTION_VIEW", "NORTH") == mathutils.Matrix( assert subject.generate_drawing_matrix("SECTION_VIEW", "NORTH") == mathutils.Matrix(
((1, 0, 0, 1), (0, 0, -1, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((1, 0, 0, 1), (0, 0, -1, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_a_south_section_at_the_cursor(self): def test_creating_a_south_section_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("SECTION_VIEW", "SOUTH") == mathutils.Matrix( assert subject.generate_drawing_matrix("SECTION_VIEW", "SOUTH") == mathutils.Matrix(
((-1, 0, 0, 1), (0, 0, 1, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((-1, 0, 0, 1), (0, 0, 1, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_an_east_section_at_the_cursor(self): def test_creating_an_east_section_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("SECTION_VIEW", "EAST") == mathutils.Matrix( assert subject.generate_drawing_matrix("SECTION_VIEW", "EAST") == mathutils.Matrix(
((0, 0, -1, 1), (-1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((0, 0, -1, 1), (-1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1))
) )
def test_creating_a_west_section_at_the_cursor(self): def test_creating_a_west_section_at_the_cursor(self):
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.generate_drawing_matrix("SECTION_VIEW", "WEST") == mathutils.Matrix( assert subject.generate_drawing_matrix("SECTION_VIEW", "WEST") == mathutils.Matrix(
((0, 0, 1, 1), (1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1)) ((0, 0, 1, 1), (1, 0, 0, 2), (0, 1, 0, 3), (0, 0, 0, 1))
@@ -598,9 +614,9 @@ class TestImportTextAttributes(NewFile):
subject.import_text_attributes(obj) subject.import_text_attributes(obj)
props = tool.Drawing.get_text_props(obj) props = tool.Drawing.get_text_props(obj)
literal_props = props.literals[0] literal_props = props.literals[0]
assert literal_props.attributes.get("Literal").string_value == "Literal" assert literal_props.attributes["Literal"].string_value == "Literal"
assert literal_props.attributes.get("Path").enum_value == "RIGHT" assert literal_props.attributes["Path"].enum_value == "RIGHT"
assert literal_props.attributes.get("BoxAlignment").string_value == "bottom-left" assert literal_props.attributes["BoxAlignment"].string_value == "bottom-left"
class TestImportAssignedProduct(NewFile): class TestImportAssignedProduct(NewFile):
@@ -615,7 +631,8 @@ class TestImportAssignedProduct(NewFile):
tool.Ifc.link(wall, wall_obj) tool.Ifc.link(wall, wall_obj)
tool.Ifc.link(label, label_obj) tool.Ifc.link(label, label_obj)
subject.import_assigned_product(label_obj) subject.import_assigned_product(label_obj)
assert label_obj.BIMAssignedProductProperties.relating_product == wall_obj props = subject.get_object_assigned_product_props(label_obj)
assert props.relating_product == wall_obj
def test_doing_nothing_if_no_product_to_import(self): def test_doing_nothing_if_no_product_to_import(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -624,7 +641,8 @@ class TestImportAssignedProduct(NewFile):
label_obj = bpy.data.objects.new("Object", None) label_obj = bpy.data.objects.new("Object", None)
tool.Ifc.link(label, label_obj) tool.Ifc.link(label, label_obj)
subject.import_assigned_product(label_obj) subject.import_assigned_product(label_obj)
assert label_obj.BIMAssignedProductProperties.relating_product is None props = subject.get_object_assigned_product_props(label_obj)
assert props.relating_product is None
class TestOpenSchedule(NewFile): class TestOpenSchedule(NewFile):
+20 -19
View File
@@ -59,13 +59,13 @@ class TestImportProjectedCRS(NewFile):
projected_crs.MapUnit = unit projected_crs.MapUnit = unit
subject.import_projected_crs() subject.import_projected_crs()
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
assert props.projected_crs.get("Name").string_value == "Name" assert props.projected_crs["Name"].string_value == "Name"
assert props.projected_crs.get("Description").string_value == "Description" assert props.projected_crs["Description"].string_value == "Description"
assert props.projected_crs.get("GeodeticDatum").string_value == "GeodeticDatum" assert props.projected_crs["GeodeticDatum"].string_value == "GeodeticDatum"
assert props.projected_crs.get("VerticalDatum").string_value == "VerticalDatum" assert props.projected_crs["VerticalDatum"].string_value == "VerticalDatum"
assert props.projected_crs.get("MapProjection").string_value == "MapProjection" assert props.projected_crs["MapProjection"].string_value == "MapProjection"
assert props.projected_crs.get("MapZone").string_value == "MapZone" assert props.projected_crs["MapZone"].string_value == "MapZone"
assert props.projected_crs.get("MapUnit").enum_value == str(unit.id()) assert props.projected_crs["MapUnit"].enum_value == str(unit.id())
def test_run_ifc2x3(self): def test_run_ifc2x3(self):
ifc = ifcopenshell.file(schema="IFC2X3") ifc = ifcopenshell.file(schema="IFC2X3")
@@ -100,13 +100,13 @@ class TestImportCoordinateOperation(NewFile):
map_conversion.Scale = 6 map_conversion.Scale = 6
subject.import_coordinate_operation() subject.import_coordinate_operation()
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
assert props.coordinate_operation.get("Eastings").string_value == "1.0" assert props.coordinate_operation["Eastings"].string_value == "1.0"
assert props.coordinate_operation.get("Northings").string_value == "2.0" assert props.coordinate_operation["Northings"].string_value == "2.0"
assert props.coordinate_operation.get("OrthogonalHeight").string_value == "3.0" assert props.coordinate_operation["OrthogonalHeight"].string_value == "3.0"
assert props.x_axis_abscissa == "4.0" assert props.x_axis_abscissa == "4.0"
assert props.x_axis_ordinate == "5.0" assert props.x_axis_ordinate == "5.0"
assert props.grid_north_angle == "-51.3401917" assert props.grid_north_angle == "-51.3401917"
assert props.coordinate_operation.get("Scale").string_value == "6.0" assert props.coordinate_operation["Scale"].string_value == "6.0"
def test_run_ifc2x3(self): def test_run_ifc2x3(self):
ifc = ifcopenshell.file(schema="IFC2X3") ifc = ifcopenshell.file(schema="IFC2X3")
@@ -220,6 +220,7 @@ class TestGetCursorLocation(NewFile):
ifcopenshell.api.run("context.add_context", ifc, context_type="Model") ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI") unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI")
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit]) ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
assert bpy.context.scene
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0) bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
assert subject.get_cursor_location() == [1000.0, 2000.0, 3000.0] assert subject.get_cursor_location() == [1000.0, 2000.0, 3000.0]
@@ -229,7 +230,7 @@ class TestXyz2Enh(NewFile):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject") ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (0.0, 0.0, 0.0) assert subject.xyz2enh((0.0, 0.0, 0.0)) == (0.0, 0.0, 0.0)
def test_using_the_blender_offset(self): def test_using_the_blender_offset(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -238,7 +239,7 @@ class TestXyz2Enh(NewFile):
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
props.has_blender_offset = True props.has_blender_offset = True
props.blender_offset_x = "1.0" props.blender_offset_x = "1.0"
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 0.0, 0.0) assert subject.xyz2enh((0.0, 0.0, 0.0)) == (1.0, 0.0, 0.0)
def test_using_the_map_conversion(self): def test_using_the_map_conversion(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -248,7 +249,7 @@ class TestXyz2Enh(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc) ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0] map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Eastings = 1.0 map_conversion.Eastings = 1.0
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 0.0, 0.0) assert subject.xyz2enh((0.0, 0.0, 0.0)) == (1.0, 0.0, 0.0)
def test_applying_both_blender_offset_and_map_conversion(self): def test_applying_both_blender_offset_and_map_conversion(self):
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
@@ -261,7 +262,7 @@ class TestXyz2Enh(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc) ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0] map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Northings = 1.0 map_conversion.Northings = 1.0
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 1.0, 0.0) assert subject.xyz2enh((0.0, 0.0, 0.0)) == (1.0, 1.0, 0.0)
class TestEnh2Xyz(NewFile): class TestEnh2Xyz(NewFile):
@@ -269,7 +270,7 @@ class TestEnh2Xyz(NewFile):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject") ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (0.0, 0.0, 0.0) assert subject.enh2xyz((0.0, 0.0, 0.0)) == (0.0, 0.0, 0.0)
def test_using_the_blender_offset(self): def test_using_the_blender_offset(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -278,7 +279,7 @@ class TestEnh2Xyz(NewFile):
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
props.has_blender_offset = True props.has_blender_offset = True
props.blender_offset_x = "1.0" props.blender_offset_x = "1.0"
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, 0.0, 0.0) assert subject.enh2xyz((0.0, 0.0, 0.0)) == (-1.0, 0.0, 0.0)
def test_using_the_map_conversion(self): def test_using_the_map_conversion(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -288,7 +289,7 @@ class TestEnh2Xyz(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc) ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0] map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Eastings = 1.0 map_conversion.Eastings = 1.0
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, 0.0, 0.0) assert subject.enh2xyz((0.0, 0.0, 0.0)) == (-1.0, 0.0, 0.0)
def test_applying_both_blender_offset_and_map_conversion(self): def test_applying_both_blender_offset_and_map_conversion(self):
props = tool.Georeference.get_georeference_props() props = tool.Georeference.get_georeference_props()
@@ -301,4 +302,4 @@ class TestEnh2Xyz(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc) ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0] map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Northings = 1.0 map_conversion.Northings = 1.0
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, -1.0, 0.0) assert subject.enh2xyz((0.0, 0.0, 0.0)) == (-1.0, -1.0, 0.0)
+10 -10
View File
@@ -79,11 +79,11 @@ class TestImportLibraryAttributes(NewFile):
library = ifc.createIfcLibraryInformation("Name", "Version", None, "VersionDate", "Location", "Description") library = ifc.createIfcLibraryInformation("Name", "Version", None, "VersionDate", "Location", "Description")
subject.import_library_attributes(library) subject.import_library_attributes(library)
props = tool.Library.get_library_props() props = tool.Library.get_library_props()
assert props.library_attributes.get("Name").string_value == "Name" assert props.library_attributes["Name"].string_value == "Name"
assert props.library_attributes.get("Version").string_value == "Version" assert props.library_attributes["Version"].string_value == "Version"
assert props.library_attributes.get("VersionDate").string_value == "VersionDate" assert props.library_attributes["VersionDate"].string_value == "VersionDate"
assert props.library_attributes.get("Location").string_value == "Location" assert props.library_attributes["Location"].string_value == "Location"
assert props.library_attributes.get("Description").string_value == "Description" assert props.library_attributes["Description"].string_value == "Description"
class TestImportReferenceAttributes(NewFile): class TestImportReferenceAttributes(NewFile):
@@ -92,11 +92,11 @@ class TestImportReferenceAttributes(NewFile):
reference = ifc.createIfcLibraryReference("Location", "Identification", "Name", "Description", "Language") reference = ifc.createIfcLibraryReference("Location", "Identification", "Name", "Description", "Language")
subject.import_reference_attributes(reference) subject.import_reference_attributes(reference)
props = tool.Library.get_library_props() props = tool.Library.get_library_props()
assert props.reference_attributes.get("Location").string_value == "Location" assert props.reference_attributes["Location"].string_value == "Location"
assert props.reference_attributes.get("Identification").string_value == "Identification" assert props.reference_attributes["Identification"].string_value == "Identification"
assert props.reference_attributes.get("Name").string_value == "Name" assert props.reference_attributes["Name"].string_value == "Name"
assert props.reference_attributes.get("Description").string_value == "Description" assert props.reference_attributes["Description"].string_value == "Description"
assert props.reference_attributes.get("Language").string_value == "Language" assert props.reference_attributes["Language"].string_value == "Language"
class TestImportReferences(NewFile): class TestImportReferences(NewFile):
+2
View File
@@ -19,7 +19,9 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.api.material import ifcopenshell.api.material
import ifcopenshell.api.root
import ifcopenshell.api.style import ifcopenshell.api.style
import ifcopenshell.api.type
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.representation import ifcopenshell.util.representation
import ifcopenshell.util.unit import ifcopenshell.util.unit
+75 -65
View File
@@ -36,7 +36,7 @@ class TestAddAddressAttribute(NewFile):
subject().add_address_attribute("FacsimileNumbers") subject().add_address_attribute("FacsimileNumbers")
subject().add_address_attribute("ElectronicMailAddresses") subject().add_address_attribute("ElectronicMailAddresses")
subject().add_address_attribute("MessagingIDs") subject().add_address_attribute("MessagingIDs")
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert len(props.address_lines) == 1 assert len(props.address_lines) == 1
assert len(props.telephone_numbers) == 1 assert len(props.telephone_numbers) == 1
assert len(props.facsimile_numbers) == 1 assert len(props.facsimile_numbers) == 1
@@ -49,7 +49,7 @@ class TestAddPersonAttribute(NewFile):
subject().add_person_attribute("MiddleNames") subject().add_person_attribute("MiddleNames")
subject().add_person_attribute("PrefixTitles") subject().add_person_attribute("PrefixTitles")
subject().add_person_attribute("SuffixTitles") subject().add_person_attribute("SuffixTitles")
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert len(props.middle_names) == 1 assert len(props.middle_names) == 1
assert len(props.prefix_titles) == 1 assert len(props.prefix_titles) == 1
assert len(props.suffix_titles) == 1 assert len(props.suffix_titles) == 1
@@ -61,7 +61,8 @@ class TestClearActor(NewFile):
actor = ifc.createIfcActor() actor = ifc.createIfcActor()
subject().set_actor(actor) subject().set_actor(actor)
subject().clear_actor() subject().clear_actor()
assert bpy.context.scene.BIMOwnerProperties.active_actor_id == 0 props = subject.get_owner_props()
assert props.active_actor_id == 0
class TestClearAddress(NewFile): class TestClearAddress(NewFile):
@@ -70,12 +71,13 @@ class TestClearAddress(NewFile):
address = ifc.createIfcPostalAddress() address = ifc.createIfcPostalAddress()
subject().set_address(address) subject().set_address(address)
subject().clear_address() subject().clear_address()
assert bpy.context.scene.BIMOwnerProperties.active_address_id == 0 props = subject.get_owner_props()
assert props.active_address_id == 0
class TestClearOrganisation(NewFile): class TestClearOrganisation(NewFile):
def test_run(self): def test_run(self):
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
props.active_organisation_id = 1 props.active_organisation_id = 1
subject().clear_organisation() subject().clear_organisation()
assert props.active_organisation_id == 0 assert props.active_organisation_id == 0
@@ -83,7 +85,7 @@ class TestClearOrganisation(NewFile):
class TestClearPerson(NewFile): class TestClearPerson(NewFile):
def test_run(self): def test_run(self):
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
props.active_person_id = 1 props.active_person_id = 1
subject().clear_person() subject().clear_person()
assert props.active_person_id == 0 assert props.active_person_id == 0
@@ -94,14 +96,16 @@ class TestClearRole(NewFile):
role = ifcopenshell.file().createIfcActorRole() role = ifcopenshell.file().createIfcActorRole()
subject().set_role(role) subject().set_role(role)
subject().clear_role() subject().clear_role()
assert bpy.context.scene.BIMOwnerProperties.active_role_id == 0 props = subject.get_owner_props()
assert props.active_role_id == 0
class TestClearUser(NewFile): class TestClearUser(NewFile):
def test_run(self): def test_run(self):
TestSetUser().test_run() TestSetUser().test_run()
subject.clear_user() subject.clear_user()
assert bpy.context.scene.BIMOwnerProperties.active_user_id == 0 props = subject.get_owner_props()
assert props.active_user_id == 0
class TestExportActorAttributes(NewFile): class TestExportActorAttributes(NewFile):
@@ -288,11 +292,11 @@ class TestImportActorAttributes(NewFile):
actor.ObjectType = "ObjectType" actor.ObjectType = "ObjectType"
subject.set_actor(actor) subject.set_actor(actor)
subject.import_actor_attributes(actor) subject.import_actor_attributes(actor)
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.actor_attributes.get("GlobalId").string_value == "GlobalId" assert props.actor_attributes["GlobalId"].string_value == "GlobalId"
assert props.actor_attributes.get("Name").string_value == "Name" assert props.actor_attributes["Name"].string_value == "Name"
assert props.actor_attributes.get("Description").string_value == "Description" assert props.actor_attributes["Description"].string_value == "Description"
assert props.actor_attributes.get("ObjectType").string_value == "ObjectType" assert props.actor_attributes["ObjectType"].string_value == "ObjectType"
def test_importing_an_occupant(self): def test_importing_an_occupant(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -305,12 +309,12 @@ class TestImportActorAttributes(NewFile):
actor.PredefinedType = "TENANT" actor.PredefinedType = "TENANT"
subject.set_actor(actor) subject.set_actor(actor)
subject.import_actor_attributes(actor) subject.import_actor_attributes(actor)
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.actor_attributes.get("GlobalId").string_value == "GlobalId" assert props.actor_attributes["GlobalId"].string_value == "GlobalId"
assert props.actor_attributes.get("Name").string_value == "Name" assert props.actor_attributes["Name"].string_value == "Name"
assert props.actor_attributes.get("Description").string_value == "Description" assert props.actor_attributes["Description"].string_value == "Description"
assert props.actor_attributes.get("ObjectType").string_value == "ObjectType" assert props.actor_attributes["ObjectType"].string_value == "ObjectType"
assert props.actor_attributes.get("PredefinedType").enum_value == "TENANT" assert props.actor_attributes["PredefinedType"].enum_value == "TENANT"
class TestImportAddressAttributes(NewFile): class TestImportAddressAttributes(NewFile):
@@ -330,16 +334,16 @@ class TestImportAddressAttributes(NewFile):
address.Country = "Country" address.Country = "Country"
subject().set_address(address) subject().set_address(address)
subject().import_address_attributes() subject().import_address_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.address_attributes.get("Purpose").enum_value == "USERDEFINED" assert props.address_attributes["Purpose"].enum_value == "USERDEFINED"
assert props.address_attributes.get("Description").string_value == "Description" assert props.address_attributes["Description"].string_value == "Description"
assert props.address_attributes.get("UserDefinedPurpose").string_value == "UserDefinedPurpose" assert props.address_attributes["UserDefinedPurpose"].string_value == "UserDefinedPurpose"
assert props.address_attributes.get("InternalLocation").string_value == "InternalLocation" assert props.address_attributes["InternalLocation"].string_value == "InternalLocation"
assert props.address_attributes.get("PostalBox").string_value == "PostalBox" assert props.address_attributes["PostalBox"].string_value == "PostalBox"
assert props.address_attributes.get("Town").string_value == "Town" assert props.address_attributes["Town"].string_value == "Town"
assert props.address_attributes.get("Region").string_value == "Region" assert props.address_attributes["Region"].string_value == "Region"
assert props.address_attributes.get("PostalCode").string_value == "PostalCode" assert props.address_attributes["PostalCode"].string_value == "PostalCode"
assert props.address_attributes.get("Country").string_value == "Country" assert props.address_attributes["Country"].string_value == "Country"
assert len(props.address_lines) == 2 assert len(props.address_lines) == 2
assert props.address_lines[0].name == "Address" assert props.address_lines[0].name == "Address"
assert props.address_lines[1].name == "Lines" assert props.address_lines[1].name == "Lines"
@@ -351,8 +355,8 @@ class TestImportAddressAttributes(NewFile):
address.Purpose = "OFFICE" address.Purpose = "OFFICE"
subject().set_address(address) subject().set_address(address)
subject().import_address_attributes() subject().import_address_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.address_attributes.get("Purpose").enum_value == "OFFICE" assert props.address_attributes["Purpose"].enum_value == "OFFICE"
assert len(props.address_lines) == 0 assert len(props.address_lines) == 0
def test_importing_a_telecom_address(self): def test_importing_a_telecom_address(self):
@@ -370,10 +374,10 @@ class TestImportAddressAttributes(NewFile):
address.MessagingIDs = ["Messaging", "IDs"] address.MessagingIDs = ["Messaging", "IDs"]
subject().set_address(address) subject().set_address(address)
subject().import_address_attributes() subject().import_address_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.address_attributes.get("Purpose").enum_value == "USERDEFINED" assert props.address_attributes["Purpose"].enum_value == "USERDEFINED"
assert props.address_attributes.get("Description").string_value == "Description" assert props.address_attributes["Description"].string_value == "Description"
assert props.address_attributes.get("UserDefinedPurpose").string_value == "UserDefinedPurpose" assert props.address_attributes["UserDefinedPurpose"].string_value == "UserDefinedPurpose"
assert [a.name for a in props.telephone_numbers] == ["Telephone", "Numbers"] assert [a.name for a in props.telephone_numbers] == ["Telephone", "Numbers"]
assert [a.name for a in props.facsimile_numbers] == ["Facsimile", "Numbers"] assert [a.name for a in props.facsimile_numbers] == ["Facsimile", "Numbers"]
assert [a.name for a in props.electronic_mail_addresses] == ["Electronic", "Mail", "Addresses"] assert [a.name for a in props.electronic_mail_addresses] == ["Electronic", "Mail", "Addresses"]
@@ -386,8 +390,8 @@ class TestImportAddressAttributes(NewFile):
address.Purpose = "OFFICE" address.Purpose = "OFFICE"
subject().set_address(address) subject().set_address(address)
subject().import_address_attributes() subject().import_address_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.address_attributes.get("Purpose").enum_value == "OFFICE" assert props.address_attributes["Purpose"].enum_value == "OFFICE"
assert len(props.telephone_numbers) == 0 assert len(props.telephone_numbers) == 0
assert len(props.facsimile_numbers) == 0 assert len(props.facsimile_numbers) == 0
assert len(props.electronic_mail_addresses) == 0 assert len(props.electronic_mail_addresses) == 0
@@ -404,10 +408,10 @@ class TestImportOrganisationAttributes(NewFile):
organisation.Description = "Description" organisation.Description = "Description"
subject().set_organisation(organisation) subject().set_organisation(organisation)
subject().import_organisation_attributes() subject().import_organisation_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.organisation_attributes.get("Identification").string_value == "Identification" assert props.organisation_attributes["Identification"].string_value == "Identification"
assert props.organisation_attributes.get("Name").string_value == "Name" assert props.organisation_attributes["Name"].string_value == "Name"
assert props.organisation_attributes.get("Description").string_value == "Description" assert props.organisation_attributes["Description"].string_value == "Description"
def test_overwriting_a_previous_import(self): def test_overwriting_a_previous_import(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -420,9 +424,9 @@ class TestImportOrganisationAttributes(NewFile):
organisation.Identification = "Identification2" organisation.Identification = "Identification2"
organisation.Description = None organisation.Description = None
subject().import_organisation_attributes() subject().import_organisation_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.organisation_attributes.get("Identification").string_value == "Identification2" assert props.organisation_attributes["Identification"].string_value == "Identification2"
assert props.organisation_attributes.get("Description").string_value == "" assert props.organisation_attributes["Description"].string_value == ""
class TestImportPersonAttributes(NewFile): class TestImportPersonAttributes(NewFile):
@@ -438,10 +442,10 @@ class TestImportPersonAttributes(NewFile):
person.SuffixTitles = ("suffix", "titles") person.SuffixTitles = ("suffix", "titles")
subject().set_person(person) subject().set_person(person)
subject().import_person_attributes() subject().import_person_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.person_attributes.get("Identification").string_value == "identification" assert props.person_attributes["Identification"].string_value == "identification"
assert props.person_attributes.get("GivenName").string_value == "given_name" assert props.person_attributes["GivenName"].string_value == "given_name"
assert props.person_attributes.get("FamilyName").string_value == "family_name" assert props.person_attributes["FamilyName"].string_value == "family_name"
assert len(props.middle_names) == 2 assert len(props.middle_names) == 2
assert props.middle_names[0].name == "middle" assert props.middle_names[0].name == "middle"
assert props.middle_names[1].name == "names" assert props.middle_names[1].name == "names"
@@ -463,9 +467,9 @@ class TestImportPersonAttributes(NewFile):
person.Identification = "identification2" person.Identification = "identification2"
person.GivenName = None person.GivenName = None
subject().import_person_attributes() subject().import_person_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.person_attributes.get("Identification").string_value == "identification2" assert props.person_attributes["Identification"].string_value == "identification2"
assert props.person_attributes.get("GivenName").string_value == "" assert props.person_attributes["GivenName"].string_value == ""
class TestImportRoleAttributes(NewFile): class TestImportRoleAttributes(NewFile):
@@ -478,10 +482,10 @@ class TestImportRoleAttributes(NewFile):
role.Description = "Description" role.Description = "Description"
subject().set_role(role) subject().set_role(role)
subject().import_role_attributes() subject().import_role_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.role_attributes.get("Role").enum_value == "USERDEFINED" assert props.role_attributes["Role"].enum_value == "USERDEFINED"
assert props.role_attributes.get("UserDefinedRole").string_value == "UserDefinedRole" assert props.role_attributes["UserDefinedRole"].string_value == "UserDefinedRole"
assert props.role_attributes.get("Description").string_value == "Description" assert props.role_attributes["Description"].string_value == "Description"
def test_importing_twice(self): def test_importing_twice(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -492,8 +496,8 @@ class TestImportRoleAttributes(NewFile):
subject().import_role_attributes() subject().import_role_attributes()
role.Role = "ARCHITECT" role.Role = "ARCHITECT"
subject().import_role_attributes() subject().import_role_attributes()
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert props.role_attributes.get("Role").enum_value == "ARCHITECT" assert props.role_attributes["Role"].enum_value == "ARCHITECT"
class TestRemoveAddressAttribute(NewFile): class TestRemoveAddressAttribute(NewFile):
@@ -503,7 +507,7 @@ class TestRemoveAddressAttribute(NewFile):
subject().remove_address_attribute("FacsimileNumbers", 0) subject().remove_address_attribute("FacsimileNumbers", 0)
subject().remove_address_attribute("ElectronicMailAddresses", 0) subject().remove_address_attribute("ElectronicMailAddresses", 0)
subject().remove_address_attribute("MessagingIDs", 0) subject().remove_address_attribute("MessagingIDs", 0)
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert len(props.address_lines) == 0 assert len(props.address_lines) == 0
assert len(props.telephone_numbers) == 0 assert len(props.telephone_numbers) == 0
assert len(props.facsimile_numbers) == 0 assert len(props.facsimile_numbers) == 0
@@ -519,7 +523,7 @@ class TestRemovePersonAttribute(NewFile):
subject().remove_person_attribute("PrefixTitles", 0) subject().remove_person_attribute("PrefixTitles", 0)
subject().add_person_attribute("SuffixTitles") subject().add_person_attribute("SuffixTitles")
subject().remove_person_attribute("SuffixTitles", 0) subject().remove_person_attribute("SuffixTitles", 0)
props = bpy.context.scene.BIMOwnerProperties props = subject.get_owner_props()
assert len(props.middle_names) == 0 assert len(props.middle_names) == 0
assert len(props.prefix_titles) == 0 assert len(props.prefix_titles) == 0
assert len(props.suffix_titles) == 0 assert len(props.suffix_titles) == 0
@@ -530,7 +534,8 @@ class TestSetActor(NewFile):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
actor = ifc.createIfcActor() actor = ifc.createIfcActor()
subject().set_actor(actor) subject().set_actor(actor)
assert bpy.context.scene.BIMOwnerProperties.active_actor_id == actor.id() props = subject.get_owner_props()
assert props.active_actor_id == actor.id()
class TestSetAddress(NewFile): class TestSetAddress(NewFile):
@@ -538,28 +543,32 @@ class TestSetAddress(NewFile):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
address = ifc.createIfcPostalAddress() address = ifc.createIfcPostalAddress()
subject().set_address(address) subject().set_address(address)
assert bpy.context.scene.BIMOwnerProperties.active_address_id == address.id() props = subject.get_owner_props()
assert props.active_address_id == address.id()
class TestSetOrganisation(NewFile): class TestSetOrganisation(NewFile):
def test_run(self): def test_run(self):
organisation = ifcopenshell.file().createIfcOrganization() organisation = ifcopenshell.file().createIfcOrganization()
subject().set_organisation(organisation) subject().set_organisation(organisation)
assert bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id() props = subject.get_owner_props()
assert props.active_organisation_id == organisation.id()
class TestSetPerson(NewFile): class TestSetPerson(NewFile):
def test_run(self): def test_run(self):
person = ifcopenshell.file().createIfcPerson() person = ifcopenshell.file().createIfcPerson()
subject().set_person(person) subject().set_person(person)
assert bpy.context.scene.BIMOwnerProperties.active_person_id == person.id() props = subject.get_owner_props()
assert props.active_person_id == person.id()
class TestSetRole(NewFile): class TestSetRole(NewFile):
def test_run(self): def test_run(self):
role = ifcopenshell.file().createIfcActorRole() role = ifcopenshell.file().createIfcActorRole()
subject().set_role(role) subject().set_role(role)
assert bpy.context.scene.BIMOwnerProperties.active_role_id == role.id() props = subject.get_owner_props()
assert props.active_role_id == role.id()
class TestSetUser(NewFile): class TestSetUser(NewFile):
@@ -568,4 +577,5 @@ class TestSetUser(NewFile):
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
user = ifc.createIfcPersonAndOrganization() user = ifc.createIfcPersonAndOrganization()
subject.set_user(user) subject.set_user(user)
assert bpy.context.scene.BIMOwnerProperties.active_user_id == user.id() props = subject.get_owner_props()
assert props.active_user_id == user.id()
+6 -6
View File
@@ -391,8 +391,8 @@ class TestImportSurfaceAttributes(NewFile):
props = tool.Style.get_style_props() props = tool.Style.get_style_props()
style = ifc.create_entity("IfcSurfaceStyle", "Name", "BOTH") style = ifc.create_entity("IfcSurfaceStyle", "Name", "BOTH")
subject.import_surface_attributes(style) subject.import_surface_attributes(style)
assert props.attributes.get("Name").string_value == "Name" assert props.attributes["Name"].string_value == "Name"
assert props.attributes.get("Side").enum_value == "BOTH" assert props.attributes["Side"].enum_value == "BOTH"
def test_importing_surface_attributes_twice(self): def test_importing_surface_attributes_twice(self):
tool.Ifc.set(ifc := ifcopenshell.file()) tool.Ifc.set(ifc := ifcopenshell.file())
@@ -400,12 +400,12 @@ class TestImportSurfaceAttributes(NewFile):
props = tool.Style.get_style_props() props = tool.Style.get_style_props()
subject.import_surface_attributes(style) subject.import_surface_attributes(style)
assert len(props.attributes) == 2 assert len(props.attributes) == 2
assert props.attributes.get("Name").string_value == "Name" assert props.attributes["Name"].string_value == "Name"
assert props.attributes.get("Side").enum_value == "BOTH" assert props.attributes["Side"].enum_value == "BOTH"
subject.import_surface_attributes(style) subject.import_surface_attributes(style)
assert len(props.attributes) == 2 assert len(props.attributes) == 2
assert props.attributes.get("Name").string_value == "Name" assert props.attributes["Name"].string_value == "Name"
assert props.attributes.get("Side").enum_value == "BOTH" assert props.attributes["Side"].enum_value == "BOTH"
class TestImportPresentationStyles(NewFile): class TestImportPresentationStyles(NewFile):
+21 -17
View File
@@ -19,6 +19,7 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.unit
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import numpy as np import numpy as np
@@ -43,6 +44,7 @@ class TestAddPorts(NewFile):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
obj.matrix_world = Euler((pi / 2, 0, pi / 2)).to_matrix().to_4x4() @ obj.matrix_world obj.matrix_world = Euler((pi / 2, 0, pi / 2)).to_matrix().to_4x4() @ obj.matrix_world
# move origin # move origin
assert isinstance(obj.data, bpy.types.Mesh)
for v in obj.data.vertices: for v in obj.data.vertices:
v.co += Vector((0, 0, 2.5)) v.co += Vector((0, 0, 2.5))
return obj, element return obj, element
@@ -90,6 +92,7 @@ class TestAddPorts(NewFile):
class TestCreateEmptyAtCursorWithElementOrientation(NewFile): class TestCreateEmptyAtCursorWithElementOrientation(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc().set(ifc) tool.Ifc().set(ifc)
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
@@ -175,10 +178,10 @@ class TestImportSystemAttributes(NewFile):
system.ObjectType = "ObjectType" system.ObjectType = "ObjectType"
subject().import_system_attributes(system) subject().import_system_attributes(system)
props = tool.System.get_system_props() props = tool.System.get_system_props()
assert props.system_attributes.get("GlobalId").string_value == "GlobalId" assert props.system_attributes["GlobalId"].string_value == "GlobalId"
assert props.system_attributes.get("Name").string_value == "Name" assert props.system_attributes["Name"].string_value == "Name"
assert props.system_attributes.get("Description").string_value == "Description" assert props.system_attributes["Description"].string_value == "Description"
assert props.system_attributes.get("ObjectType").string_value == "ObjectType" assert props.system_attributes["ObjectType"].string_value == "ObjectType"
def test_importing_a_building_system(self): def test_importing_a_building_system(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -192,12 +195,12 @@ class TestImportSystemAttributes(NewFile):
system.LongName = "LongName" system.LongName = "LongName"
subject().import_system_attributes(system) subject().import_system_attributes(system)
props = tool.System.get_system_props() props = tool.System.get_system_props()
assert props.system_attributes.get("GlobalId").string_value == "GlobalId" assert props.system_attributes["GlobalId"].string_value == "GlobalId"
assert props.system_attributes.get("Name").string_value == "Name" assert props.system_attributes["Name"].string_value == "Name"
assert props.system_attributes.get("Description").string_value == "Description" assert props.system_attributes["Description"].string_value == "Description"
assert props.system_attributes.get("ObjectType").string_value == "ObjectType" assert props.system_attributes["ObjectType"].string_value == "ObjectType"
assert props.system_attributes.get("PredefinedType").enum_value == "SHADING" assert props.system_attributes["PredefinedType"].enum_value == "SHADING"
assert props.system_attributes.get("LongName").string_value == "LongName" assert props.system_attributes["LongName"].string_value == "LongName"
def test_importing_a_distribution_system(self): def test_importing_a_distribution_system(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
@@ -211,12 +214,12 @@ class TestImportSystemAttributes(NewFile):
system.LongName = "LongName" system.LongName = "LongName"
subject().import_system_attributes(system) subject().import_system_attributes(system)
props = tool.System.get_system_props() props = tool.System.get_system_props()
assert props.system_attributes.get("GlobalId").string_value == "GlobalId" assert props.system_attributes["GlobalId"].string_value == "GlobalId"
assert props.system_attributes.get("Name").string_value == "Name" assert props.system_attributes["Name"].string_value == "Name"
assert props.system_attributes.get("Description").string_value == "Description" assert props.system_attributes["Description"].string_value == "Description"
assert props.system_attributes.get("ObjectType").string_value == "ObjectType" assert props.system_attributes["ObjectType"].string_value == "ObjectType"
assert props.system_attributes.get("PredefinedType").enum_value == "ELECTRICAL" assert props.system_attributes["PredefinedType"].enum_value == "ELECTRICAL"
assert props.system_attributes.get("LongName").string_value == "LongName" assert props.system_attributes["LongName"].string_value == "LongName"
class TestImportSystems(NewFile): class TestImportSystems(NewFile):
@@ -245,7 +248,7 @@ class TestLoadPorts(NewFile):
port = ifc.create_entity("IfcDistributionPort") port = ifc.create_entity("IfcDistributionPort")
subject.load_ports(element, [port]) subject.load_ports(element, [port])
obj = tool.Ifc.get_object(port) obj = tool.Ifc.get_object(port)
assert obj assert isinstance(obj, bpy.types.Object)
assert obj.users_collection assert obj.users_collection
assert list(obj.location) == [0, 0, 0] assert list(obj.location) == [0, 0, 0]
@@ -262,6 +265,7 @@ class TestRunRootAssignClass(NewFile):
class TestSelectSystemProducts(NewFile): class TestSelectSystemProducts(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc().set(ifc) tool.Ifc().set(ifc)
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump")
+5 -3
View File
@@ -18,6 +18,8 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.api.root
import ifcopenshell.api.type
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
@@ -153,9 +155,9 @@ class TestGetTypeOccurrences(NewFile):
def test_run(self): def test_run(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") wall_type = ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcWallType")
wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall = ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcWall")
ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) ifcopenshell.api.type.assign_type(ifc, related_objects=[wall], relating_type=wall_type)
assert subject.get_type_occurrences(wall_type) == (wall,) assert subject.get_type_occurrences(wall_type) == (wall,)
+4
View File
@@ -104,6 +104,7 @@ class TestExportUnitAttributes(NewFile):
class TestGetSceneUnitName(NewFile): class TestGetSceneUnitName(NewFile):
def test_getting_an_imperial_name(self): def test_getting_an_imperial_name(self):
assert bpy.context.scene
props = tool.Blender.get_bim_props() props = tool.Blender.get_bim_props()
bpy.context.scene.unit_settings.system = "IMPERIAL" bpy.context.scene.unit_settings.system = "IMPERIAL"
bpy.context.scene.unit_settings.length_unit = "MILES" bpy.context.scene.unit_settings.length_unit = "MILES"
@@ -130,12 +131,14 @@ class TestGetSceneUnitName(NewFile):
assert subject.get_scene_unit_name("VOLUMEUNIT") == "cubic inch" assert subject.get_scene_unit_name("VOLUMEUNIT") == "cubic inch"
def test_getting_a_name_with_no_unit_system(self): def test_getting_a_name_with_no_unit_system(self):
assert bpy.context.scene
bpy.context.scene.unit_settings.system = "NONE" bpy.context.scene.unit_settings.system = "NONE"
assert subject.get_scene_unit_name("LENGTHUNIT") == "foot" assert subject.get_scene_unit_name("LENGTHUNIT") == "foot"
class TestGetSceneUnitSIPrefix: class TestGetSceneUnitSIPrefix:
def test_run(self): def test_run(self):
assert bpy.context.scene
bpy.context.scene.unit_settings.system = "METRIC" bpy.context.scene.unit_settings.system = "METRIC"
bpy.context.scene.unit_settings.length_unit = "METERS" bpy.context.scene.unit_settings.length_unit = "METERS"
assert subject.get_scene_unit_si_prefix("LENGTHUNIT") is None assert subject.get_scene_unit_si_prefix("LENGTHUNIT") is None
@@ -298,6 +301,7 @@ class TestImportUnits(NewFile):
class TestIsSceneUnitMetric(NewFile): class TestIsSceneUnitMetric(NewFile):
def test_run(self): def test_run(self):
assert bpy.context.scene
props = bpy.context.scene.unit_settings props = bpy.context.scene.unit_settings
props.system = "METRIC" props.system = "METRIC"
assert subject.is_scene_unit_metric() is True assert subject.is_scene_unit_metric() is True