mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
typing
This commit is contained in:
@@ -1076,9 +1076,10 @@ class IfcImporter:
|
||||
print(traceback.format_exc())
|
||||
|
||||
def set_default_context(self):
|
||||
rprops = tool.Root.get_root_props()
|
||||
for subcontext in self.file.by_type("IfcGeometricRepresentationSubContext"):
|
||||
if subcontext.ContextIdentifier == "Body":
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(subcontext.id())
|
||||
rprops.contexts = str(subcontext.id())
|
||||
break
|
||||
|
||||
def link_element(self, element: ifcopenshell.entity_instance, obj: IFC_CONNECTED_TYPE) -> None:
|
||||
|
||||
@@ -97,7 +97,7 @@ class AuthoringData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
|
||||
@@ -58,7 +58,8 @@ class AddEmptyType(bpy.types.Operator, AddObjectHelper):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.new("TYPEX", None)
|
||||
context.scene.collection.objects.link(obj)
|
||||
context.scene.BIMRootProperties.ifc_product = "IfcElementType"
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.ifc_product = "IfcElementType"
|
||||
tool.Blender.select_and_activate_single_object(context, obj)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -71,7 +72,7 @@ class AddDefaultType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifc_element_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
props.ifc_product = "IfcElementType"
|
||||
props.ifc_class = self.ifc_element_type
|
||||
if self.ifc_element_type == "IfcWallType":
|
||||
@@ -363,7 +364,7 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
bonsai.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||
|
||||
rprops = context.scene.BIMRootProperties
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_context = None
|
||||
if get_enum_items(rprops, "contexts", context):
|
||||
ifc_context = int(rprops.contexts or "0") or None
|
||||
|
||||
@@ -60,7 +60,8 @@ class IfcClassData:
|
||||
|
||||
@classmethod
|
||||
def ifc_classes(cls):
|
||||
ifc_product = bpy.context.scene.BIMRootProperties.ifc_product
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_product = rprops.ifc_product
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
|
||||
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
|
||||
names = [d.name() for d in declarations]
|
||||
@@ -80,7 +81,8 @@ class IfcClassData:
|
||||
@classmethod
|
||||
def ifc_predefined_types(cls):
|
||||
types_enum = []
|
||||
ifc_class = bpy.context.scene.BIMRootProperties.ifc_class
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_class = rprops.ifc_class
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_class)
|
||||
version = tool.Ifc.get_schema()
|
||||
for attribute in declaration.attributes():
|
||||
@@ -114,7 +116,8 @@ class IfcClassData:
|
||||
|
||||
@classmethod
|
||||
def representation_template(cls):
|
||||
ifc_class = bpy.context.scene.BIMRootProperties.ifc_class
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_class = rprops.ifc_class
|
||||
templates = [
|
||||
("EMPTY", "No Geometry", "Start with an empty object"),
|
||||
None,
|
||||
|
||||
@@ -42,6 +42,7 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
rprops = tool.Root.get_root_props()
|
||||
obj = context.active_object
|
||||
self.file = tool.Ifc.get()
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -53,7 +54,7 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
declaration = schema.declaration_by_name(ifc_class)
|
||||
for ifc_product in ifc_products:
|
||||
if ifcopenshell.util.schema.is_a(declaration, ifc_product):
|
||||
context.scene.BIMRootProperties.ifc_product = ifc_product
|
||||
rprops.ifc_product = ifc_product
|
||||
break
|
||||
else:
|
||||
self.report({"ERROR"}, f"Couldn't find matching IFC product for the selected object: '{element}'.")
|
||||
@@ -61,13 +62,13 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
return {"CANCELLED"}
|
||||
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
context.scene.BIMRootProperties.ifc_class = element.is_a()
|
||||
context.scene.BIMRootProperties.relating_class_object = None
|
||||
rprops.ifc_class = element.is_a()
|
||||
rprops.relating_class_object = None
|
||||
if hasattr(element, "PredefinedType"):
|
||||
if element.PredefinedType:
|
||||
context.scene.BIMRootProperties.ifc_predefined_type = element.PredefinedType
|
||||
rprops.ifc_predefined_type = element.PredefinedType
|
||||
userdefined_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||
context.scene.BIMRootProperties.ifc_userdefined_type = userdefined_type or ""
|
||||
rprops.ifc_userdefined_type = userdefined_type or ""
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -94,9 +95,9 @@ class ReassignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
objects = set(context.selected_objects + [context.active_object])
|
||||
self.file = tool.Ifc.get()
|
||||
root_props = context.scene.BIMRootProperties
|
||||
ifc_product: str = root_props.ifc_product
|
||||
ifc_class: str = root_props.ifc_class
|
||||
root_props = tool.Root.get_root_props()
|
||||
ifc_product = root_props.ifc_product
|
||||
ifc_class = root_props.ifc_class
|
||||
type_ifc_class = next(iter(ifcopenshell.util.type.get_applicable_types(ifc_class, self.file.schema)), None)
|
||||
|
||||
predefined_type = root_props.ifc_predefined_type
|
||||
@@ -176,7 +177,7 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifc_representation_class: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
objects: list[bpy.types.Object] = []
|
||||
if self.obj:
|
||||
objects = [bpy.data.objects[self.obj]]
|
||||
@@ -358,7 +359,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE")
|
||||
|
||||
def _invoke(self, context, event):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
# For convenience, preselect OBJs if applicable
|
||||
if props.ifc_product == "IfcFeatureElement":
|
||||
if (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
@@ -376,7 +377,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
predefined_type = (
|
||||
props.ifc_userdefined_type if props.ifc_predefined_type == "USERDEFINED" else props.ifc_predefined_type
|
||||
)
|
||||
@@ -500,7 +501,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
material = ifcopenshell.api.run("material.add_material", tool.Ifc.get(), name="Unknown")
|
||||
if representation_template == "PROFILESET":
|
||||
profile_id = tool.Blender.get_enum_safe(context.scene.BIMRootProperties, "profile")
|
||||
profile_id = tool.Blender.get_enum_safe(props, "profile")
|
||||
if profile_id in ("-", None):
|
||||
profile = next((p for p in ifc_file.by_type("IfcProfileDef") if p.ProfileName), None)
|
||||
if profile is None:
|
||||
@@ -589,7 +590,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Blender.set_active_object(obj)
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
self.layout.use_property_split = True
|
||||
self.layout.use_property_decorate = False
|
||||
row = self.layout.row()
|
||||
@@ -600,7 +601,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not self.ifc_product:
|
||||
prop_with_search(self.layout, props, "ifc_product", text="Definition", should_click_ok=True)
|
||||
prop_with_search(self.layout, props, "ifc_class", should_click_ok=True)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(props, context)
|
||||
if ifc_predefined_types:
|
||||
prop_with_search(self.layout, props, "ifc_predefined_type", should_click_ok=True)
|
||||
if props.ifc_predefined_type == "USERDEFINED":
|
||||
|
||||
@@ -34,28 +34,27 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
|
||||
def get_ifc_predefined_types(self, context):
|
||||
def get_ifc_predefined_types(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_predefined_types"]
|
||||
|
||||
|
||||
def get_representation_template(self, context):
|
||||
def get_representation_template(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["representation_template"]
|
||||
|
||||
|
||||
def refresh_classes(self, context):
|
||||
old_class = context.scene.BIMRootProperties.ifc_class
|
||||
old_predefined_type = (
|
||||
context.scene.BIMRootProperties.ifc_predefined_type if get_ifc_predefined_types(self, context) else ""
|
||||
)
|
||||
def refresh_classes(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
old_class = self.ifc_class
|
||||
old_predefined_type = self.ifc_predefined_type if get_ifc_predefined_types(self, context) else ""
|
||||
|
||||
enum = get_ifc_classes(self, context)
|
||||
context.scene.BIMRootProperties.ifc_class = enum[0][0]
|
||||
self.ifc_class = enum[0][0]
|
||||
IfcClassData.load()
|
||||
|
||||
if self.ifc_product == "IfcFeatureElement":
|
||||
@@ -81,48 +80,44 @@ def refresh_classes(self, context):
|
||||
self.ifc_predefined_type = old_predefined_type
|
||||
|
||||
|
||||
def refresh_predefined_types(self, context):
|
||||
def refresh_predefined_types(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
IfcClassData.load()
|
||||
enum = get_ifc_predefined_types(self, context)
|
||||
if enum:
|
||||
context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0]
|
||||
self.ifc_predefined_type = enum[0][0]
|
||||
|
||||
|
||||
def update_class_enum(self, context):
|
||||
self.ifc_class = self.ifc_class_filter_enum
|
||||
|
||||
|
||||
def get_ifc_products(self, context):
|
||||
def get_ifc_products(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_products"]
|
||||
|
||||
|
||||
def get_ifc_classes(self, context):
|
||||
def get_ifc_classes(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_classes"]
|
||||
|
||||
|
||||
def get_ifc_classes_suggestions():
|
||||
def get_ifc_classes_suggestions(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_classes_suggestions"]
|
||||
|
||||
|
||||
def get_contexts(self, context):
|
||||
def get_contexts(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["contexts"]
|
||||
|
||||
|
||||
def get_profile(self, context):
|
||||
def get_profile(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["profile"]
|
||||
|
||||
|
||||
def update_relating_class_from_object(self, context):
|
||||
def update_relating_class_from_object(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
if self.relating_class_object is None:
|
||||
return
|
||||
element = tool.Ifc.get_entity(self.relating_class_object)
|
||||
@@ -139,7 +134,7 @@ def update_relating_class_from_object(self, context):
|
||||
bpy.ops.bim.reassign_class()
|
||||
|
||||
|
||||
def is_object_class_applicable(self, obj):
|
||||
def is_object_class_applicable(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return False
|
||||
@@ -149,11 +144,11 @@ def is_object_class_applicable(self, obj):
|
||||
return element.is_a("IfcTypeObject") == active_element.is_a("IfcTypeObject")
|
||||
|
||||
|
||||
def poll_representation_obj(self, obj):
|
||||
def poll_representation_obj(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
return obj.type == "MESH" and obj.data.polygons
|
||||
|
||||
|
||||
def poll_featured_obj(self, obj):
|
||||
def poll_featured_obj(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
return tool.Ifc.get_entity(obj)
|
||||
|
||||
|
||||
@@ -192,3 +187,16 @@ class BIMRootProperties(PropertyGroup):
|
||||
getter_enum_suggestions = {
|
||||
"ifc_class": get_ifc_classes_suggestions,
|
||||
}
|
||||
|
||||
if TYPE_CHECKING:
|
||||
contexts: str
|
||||
description: str
|
||||
ifc_product: str
|
||||
ifc_class: str
|
||||
ifc_predefined_type: str
|
||||
ifc_userdefined_type: str
|
||||
featured_obj: Union[bpy.types.Object, None]
|
||||
representation_template: str
|
||||
representation_obj: Union[bpy.types.Object, None]
|
||||
profile: str
|
||||
relating_class_object: Union[bpy.types.Object, None]
|
||||
|
||||
@@ -44,6 +44,7 @@ class BIM_PT_class(Panel):
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
props = context.active_object.BIMObjectProperties
|
||||
rprops = tool.Root.get_root_props()
|
||||
if props.ifc_definition_id:
|
||||
if not IfcClassData.data["has_entity"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -58,10 +59,10 @@ class BIM_PT_class(Panel):
|
||||
row.operator("bim.disable_reassign_class", icon="CANCEL", text="")
|
||||
self.draw_class_dropdowns(
|
||||
context,
|
||||
root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context),
|
||||
root_prop.get_ifc_predefined_types(rprops, context),
|
||||
is_reassigning_class=True,
|
||||
)
|
||||
self.layout.prop(context.scene.BIMRootProperties, "relating_class_object", icon="COPYDOWN")
|
||||
self.layout.prop(rprops, "relating_class_object", icon="COPYDOWN")
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(
|
||||
@@ -78,16 +79,16 @@ class BIM_PT_class(Panel):
|
||||
if AuthoringData.data["is_representation_item_active"]:
|
||||
return
|
||||
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(rprops, context)
|
||||
self.draw_class_dropdowns(context, ifc_predefined_types)
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.assign_class")
|
||||
op.ifc_class = context.scene.BIMRootProperties.ifc_class
|
||||
op.predefined_type = context.scene.BIMRootProperties.ifc_predefined_type if ifc_predefined_types else ""
|
||||
op.userdefined_type = context.scene.BIMRootProperties.ifc_userdefined_type
|
||||
op.ifc_class = rprops.ifc_class
|
||||
op.predefined_type = rprops.ifc_predefined_type if ifc_predefined_types else ""
|
||||
op.userdefined_type = rprops.ifc_userdefined_type
|
||||
|
||||
def draw_class_dropdowns(self, context, ifc_predefined_types, is_reassigning_class=False):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
layout = self.layout
|
||||
prop_with_search(layout, props, "ifc_product")
|
||||
prop_with_search(layout, props, "ifc_class")
|
||||
|
||||
@@ -58,7 +58,7 @@ class SpatialData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
@@ -102,7 +102,7 @@ class SpatialDecompositionData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
@@ -112,7 +112,7 @@ class SpatialDecompositionData:
|
||||
@classmethod
|
||||
def subelement_class(cls) -> list[tuple[str, str, str]]:
|
||||
results = []
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if not (container := props.active_container):
|
||||
return results
|
||||
container_class = tool.Ifc.get().by_id(container.ifc_definition_id).is_a()
|
||||
|
||||
@@ -66,7 +66,8 @@ class GridDecorator:
|
||||
blf.size(font_id, 12)
|
||||
blf.enable(font_id, blf.SHADOW)
|
||||
|
||||
for axis in context.scene.BIMGridProperties.grid_axes:
|
||||
grid_props = tool.Spatial.get_grid_props()
|
||||
for axis in grid_props.grid_axes:
|
||||
if not (obj := axis.obj) or obj.hide_get() == True:
|
||||
continue
|
||||
if obj.select_get() and context.mode != "OBJECT":
|
||||
@@ -120,7 +121,8 @@ class GridDecorator:
|
||||
selected_edges = []
|
||||
unselected_verts = []
|
||||
unselected_edges = []
|
||||
for axis in context.scene.BIMGridProperties.grid_axes:
|
||||
grid_props = tool.Spatial.get_grid_props()
|
||||
for axis in grid_props.grid_axes:
|
||||
if (obj := axis.obj) and obj.hide_get() == False:
|
||||
if obj.select_get():
|
||||
if context.mode != "OBJECT":
|
||||
|
||||
@@ -96,7 +96,7 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator):
|
||||
container = tool.Ifc.get().by_id(self.container)
|
||||
elif (
|
||||
(obj := tool.Blender.get_active_object())
|
||||
and (props := obj.BIMObjectSpatialProperties)
|
||||
and (props := tool.Spatial.get_object_spatial_props(obj))
|
||||
and (container_obj := props.container_obj)
|
||||
and (container := tool.Ifc.get_entity(container_obj))
|
||||
):
|
||||
|
||||
@@ -36,15 +36,18 @@ import bonsai.core.geometry
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
from typing import TYPE_CHECKING, Union, Literal
|
||||
|
||||
|
||||
def get_subelement_class(self, context):
|
||||
def get_subelement_class(
|
||||
self: "BIMSpatialDecompositionProperties", context: bpy.types.Context
|
||||
) -> list[tuple[str, str, str]]:
|
||||
if not SpatialDecompositionData.is_loaded:
|
||||
SpatialDecompositionData.load()
|
||||
return SpatialDecompositionData.data["subelement_class"]
|
||||
|
||||
|
||||
def update_elevation(self, context):
|
||||
def update_elevation(self: "BIMContainer", context: bpy.types.Context) -> None:
|
||||
try:
|
||||
elevation = float(self.elevation)
|
||||
if self.elevation != str(elevation):
|
||||
@@ -91,7 +94,7 @@ def update_element_mode(self: "BIMSpatialDecompositionProperties", context: bpy.
|
||||
tool.Spatial.load_contained_elements()
|
||||
|
||||
|
||||
def update_grid_is_locked(self, context):
|
||||
def update_grid_is_locked(self: "BIMGridProperties", context: bpy.types.Context) -> None:
|
||||
if not tool.Ifc.get():
|
||||
return
|
||||
if tool.Ifc.get().schema in ("IFC2X3", "IFC4"):
|
||||
@@ -108,7 +111,7 @@ def update_grid_is_locked(self, context):
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
|
||||
|
||||
def update_spatial_is_locked(self, context):
|
||||
def update_spatial_is_locked(self: "BIMSpatialDecompositionProperties", context: bpy.types.Context) -> None:
|
||||
if not tool.Ifc.get():
|
||||
return
|
||||
if tool.Ifc.get().schema == "IFC2X3":
|
||||
@@ -150,6 +153,10 @@ class BIMObjectSpatialProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
container_obj: PointerProperty(type=bpy.types.Object, name="Container", poll=poll_container_obj)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
container_obj: Union[bpy.types.Object, None]
|
||||
|
||||
|
||||
class BIMContainer(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=update_name)
|
||||
@@ -162,6 +169,16 @@ class BIMContainer(PropertyGroup):
|
||||
is_expanded: BoolProperty(name="Is Expanded")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ifc_class: str
|
||||
description: str
|
||||
long_name: str
|
||||
elevation: str
|
||||
level_index: int
|
||||
has_children: bool
|
||||
is_expanded: bool
|
||||
ifc_definition_id: int
|
||||
|
||||
|
||||
class Element(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
@@ -185,6 +202,16 @@ class Element(PropertyGroup):
|
||||
),
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ifc_class: str
|
||||
identification: str
|
||||
ifc_definition_id: int
|
||||
level: int
|
||||
has_children: bool
|
||||
total: int
|
||||
is_expanded: bool
|
||||
type: Literal["CLASS", "TYPE", "CLASSIFICATION", "OCCURRENCE"]
|
||||
|
||||
|
||||
class BIMSpatialDecompositionProperties(PropertyGroup):
|
||||
is_locked: BoolProperty(
|
||||
@@ -223,6 +250,23 @@ class BIMSpatialDecompositionProperties(PropertyGroup):
|
||||
name="Should Include Children", default=True, update=update_should_include_children
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_locked: bool
|
||||
is_visible: bool
|
||||
container_filter: str
|
||||
containers: bpy.types.bpy_prop_collection_idprop[BIMContainer]
|
||||
contracted_containers: str
|
||||
active_container_index: int
|
||||
element_filter: str
|
||||
elements: bpy.types.bpy_prop_collection_idprop[Element]
|
||||
expanded_elements: str
|
||||
active_element_index: int
|
||||
total_elements: int
|
||||
element_mode: Literal["TYPE", "DECOMPOSITION", "CLASSIFICATION"]
|
||||
subelement_class: str
|
||||
default_container: int
|
||||
should_include_children: bool
|
||||
|
||||
@property
|
||||
def active_container(self):
|
||||
if self.containers and self.active_container_index < len(self.containers):
|
||||
@@ -248,3 +292,8 @@ class BIMGridProperties(PropertyGroup):
|
||||
update=update_grid_is_visible,
|
||||
)
|
||||
grid_axes: CollectionProperty(name="Grid Axes", type=ObjProperty)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_locked: bool
|
||||
is_visible: bool
|
||||
grid_axes: bpy.types.bpy_prop_collection_idprop[ObjProperty]
|
||||
|
||||
@@ -16,10 +16,15 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
from bpy.types import Panel, UIList
|
||||
from bonsai.bim.module.spatial.data import SpatialData, SpatialDecompositionData
|
||||
import bonsai.tool as tool
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.spatial.prop import BIMSpatialDecompositionProperties, BIMContainer, Element
|
||||
|
||||
|
||||
class BIM_PT_spatial(Panel):
|
||||
@@ -40,7 +45,9 @@ class BIM_PT_spatial(Panel):
|
||||
if not SpatialData.is_loaded:
|
||||
SpatialData.load()
|
||||
|
||||
osprops = context.active_object.BIMObjectSpatialProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
osprops = tool.Spatial.get_object_spatial_props(obj)
|
||||
|
||||
if osprops.is_editing:
|
||||
if SpatialData.data["default_container"]:
|
||||
@@ -103,7 +110,7 @@ class BIM_PT_spatial_decomposition(Panel):
|
||||
return tool.Ifc.get()
|
||||
|
||||
def draw_header(self, context):
|
||||
props = context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="") # empty text occupies the left of the row
|
||||
icon = "HIDE_OFF" if props.is_visible else "HIDE_ON"
|
||||
@@ -114,7 +121,7 @@ class BIM_PT_spatial_decomposition(Panel):
|
||||
def draw(self, context):
|
||||
if not SpatialDecompositionData.is_loaded:
|
||||
SpatialDecompositionData.load()
|
||||
self.props = context.scene.BIMSpatialDecompositionProperties
|
||||
self.props = tool.Spatial.get_spatial_props()
|
||||
|
||||
if SpatialDecompositionData.data["default_container"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -233,7 +240,7 @@ class BIM_PT_grids(Panel):
|
||||
self.layout.row().operator("mesh.add_grid", icon="ADD", text="Add Grids")
|
||||
|
||||
def draw_header(self, context):
|
||||
props = context.scene.BIMGridProperties
|
||||
props = tool.Spatial.get_grid_props()
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="") # empty text occupies the left of the row
|
||||
icon = "HIDE_OFF" if props.is_visible else "HIDE_ON"
|
||||
@@ -243,25 +250,36 @@ class BIM_PT_grids(Panel):
|
||||
|
||||
|
||||
class BIM_UL_containers_manager(UIList):
|
||||
icon_by_class = {
|
||||
"IfcProject": "FILE",
|
||||
"IfcSite": "WORLD",
|
||||
"IfcBuilding": "HOME",
|
||||
"IfcBuildingStorey": "LINENUMBERS_OFF",
|
||||
"IfcSpace": "ANTIALIASED",
|
||||
"IfcFacilityPart": "MOD_FLUID",
|
||||
"IfcBridgePart": "MOD_FLUID",
|
||||
"IfcFacilityPartCommon": "MOD_FLUID",
|
||||
"IfcMarinePart": "MOD_FLUID",
|
||||
"IfcRailwayPart": "MOD_FLUID",
|
||||
"IfcRoadPart": "MOD_FLUID",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.use_filter_show = True
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMSpatialDecompositionProperties,
|
||||
item: BIMContainer,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
icon = {
|
||||
"IfcProject": "FILE",
|
||||
"IfcSite": "WORLD",
|
||||
"IfcBuilding": "HOME",
|
||||
"IfcBuildingStorey": "LINENUMBERS_OFF",
|
||||
"IfcSpace": "ANTIALIASED",
|
||||
"IfcFacilityPart": "MOD_FLUID",
|
||||
"IfcBridgePart": "MOD_FLUID",
|
||||
"IfcFacilityPartCommon": "MOD_FLUID",
|
||||
"IfcMarinePart": "MOD_FLUID",
|
||||
"IfcRailwayPart": "MOD_FLUID",
|
||||
"IfcRoadPart": "MOD_FLUID",
|
||||
}.get(item.ifc_class, "META_PLANE")
|
||||
icon = self.icon_by_class.get(item.ifc_class, "META_PLANE")
|
||||
split = row.split(factor=0.85)
|
||||
if item.long_name:
|
||||
split2 = split.split(factor=0.7)
|
||||
@@ -275,7 +293,7 @@ class BIM_UL_containers_manager(UIList):
|
||||
row.prop(item, "name", emboss=False, text="", icon=icon)
|
||||
split.prop(item, "elevation", emboss=False, text="")
|
||||
|
||||
def draw_hierarchy(self, row, item):
|
||||
def draw_hierarchy(self, row: bpy.types.UILayout, item: BIMContainer) -> None:
|
||||
if item.level_index:
|
||||
for i in range(0, item.level_index - 1):
|
||||
row.label(text="", icon="BLANK1")
|
||||
@@ -293,11 +311,12 @@ class BIM_UL_containers_manager(UIList):
|
||||
|
||||
def draw_filter(self, context, layout):
|
||||
row = layout.row()
|
||||
row.prop(context.scene.BIMSpatialDecompositionProperties, "container_filter", text="", icon="VIEWZOOM")
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row.prop(props, "container_filter", text="", icon="VIEWZOOM")
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
def filter_items(self, context: bpy.types.Context, data: BIMSpatialDecompositionProperties, propname: str):
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.container_filter.lower()
|
||||
filter_name = data.container_filter.lower()
|
||||
filter_flags = [self.bitflag_filter_item] * len(items)
|
||||
|
||||
for idx, item in enumerate(items):
|
||||
@@ -313,7 +332,7 @@ class BIM_UL_containers_manager(UIList):
|
||||
return filter_flags, []
|
||||
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.container_filter
|
||||
filter_name = data.container_filter
|
||||
filtered = bpy.types.UI_UL_list.filter_items_by_name(filter_name, self.bitflag_filter_item, items, "name")
|
||||
return filtered, []
|
||||
|
||||
@@ -326,7 +345,18 @@ class BIM_UL_elements(UIList):
|
||||
icon_id = "DISCLOSURE_TRI_DOWN" if is_expanded else "DISCLOSURE_TRI_RIGHT"
|
||||
row.operator("bim.toggle_container_element", text="", emboss=False, icon=icon_id).element_index = index
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, fit_flag):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMSpatialDecompositionProperties,
|
||||
item: Element,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
index,
|
||||
fit_flag,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
for _ in range(item.level):
|
||||
@@ -341,11 +371,12 @@ class BIM_UL_elements(UIList):
|
||||
|
||||
def draw_filter(self, context, layout):
|
||||
row = layout.row()
|
||||
row.prop(context.scene.BIMSpatialDecompositionProperties, "element_filter", text="", icon="VIEWZOOM")
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row.prop(props, "element_filter", text="", icon="VIEWZOOM")
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
def filter_items(self, context: bpy.types.Context, data: BIMSpatialDecompositionProperties, propname: str):
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.element_filter
|
||||
filter_name = data.element_filter
|
||||
filtered = bpy.types.UI_UL_list.filter_items_by_name(filter_name, self.bitflag_filter_item, items, "name")
|
||||
return filtered, []
|
||||
|
||||
|
||||
@@ -147,11 +147,11 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
def is_locked(cls, element: ifcopenshell.entity_instance) -> bool:
|
||||
if element.is_a("IfcProject"):
|
||||
return True
|
||||
elif tool.Root.is_spatial_element(element) and bpy.context.scene.BIMSpatialDecompositionProperties.is_locked:
|
||||
elif tool.Root.is_spatial_element(element) and tool.Spatial.get_spatial_props().is_locked:
|
||||
return True
|
||||
elif (
|
||||
element.is_a("IfcPositioningElement") or element.is_a("IfcGrid") or element.is_a("IfcGridAxis")
|
||||
) and bpy.context.scene.BIMGridProperties.is_locked:
|
||||
) and tool.Spatial.get_grid_props().is_locked:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -137,13 +137,15 @@ class Project(bonsai.core.tool.Project):
|
||||
@classmethod
|
||||
def set_context(cls, context):
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.contexts = str(context.id())
|
||||
|
||||
@classmethod
|
||||
def set_default_context(cls):
|
||||
context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||
if context:
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.contexts = str(context.id())
|
||||
|
||||
@classmethod
|
||||
def set_default_modeling_dimensions(cls):
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
@@ -27,12 +28,19 @@ import bonsai.core.tool
|
||||
import bonsai.core.aggregate
|
||||
import bonsai.core.geometry
|
||||
import bonsai.tool as tool
|
||||
from typing import Union, Optional, Any, Literal
|
||||
from typing import Union, Optional, Any, Literal, TYPE_CHECKING
|
||||
from bonsai.bim.module.spatial.decorator import GridDecorator
|
||||
from bonsai.bim.module.geometry.decorator import ItemDecorator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.root.prop import BIMRootProperties
|
||||
|
||||
|
||||
class Root(bonsai.core.tool.Root):
|
||||
@classmethod
|
||||
def get_root_props(cls) -> BIMRootProperties:
|
||||
return bpy.context.scene.BIMRootProperties
|
||||
|
||||
@classmethod
|
||||
def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None:
|
||||
"""Add tracked opening or boolean object."""
|
||||
@@ -112,7 +120,7 @@ class Root(bonsai.core.tool.Root):
|
||||
|
||||
@classmethod
|
||||
def get_default_container(cls) -> Optional[ifcopenshell.entity_instance]:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if container := props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(container)
|
||||
@@ -233,7 +241,7 @@ class Root(bonsai.core.tool.Root):
|
||||
|
||||
@classmethod
|
||||
def reload_grid_decorator(cls) -> None:
|
||||
axes = bpy.context.scene.BIMGridProperties.grid_axes
|
||||
axes = tool.Spatial.get_grid_props().grid_axes
|
||||
axes.clear()
|
||||
for axis in tool.Ifc.get().by_type("IfcGridAxis"):
|
||||
if obj := tool.Ifc.get_object(axis):
|
||||
|
||||
@@ -41,12 +41,31 @@ import json
|
||||
from math import pi
|
||||
from mathutils import Vector, Matrix
|
||||
from shapely import Polygon
|
||||
from typing import Generator, Optional, Union, Literal, List, Any, Iterable
|
||||
from typing import Generator, Optional, Union, Literal, List, Any, Iterable, TYPE_CHECKING
|
||||
from collections import defaultdict
|
||||
from natsort import natsorted
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.spatial.prop import (
|
||||
BIMGridProperties,
|
||||
BIMSpatialDecompositionProperties,
|
||||
BIMObjectSpatialProperties,
|
||||
)
|
||||
|
||||
|
||||
class Spatial(bonsai.core.tool.Spatial):
|
||||
@classmethod
|
||||
def get_spatial_props(cls) -> BIMSpatialDecompositionProperties:
|
||||
return bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
|
||||
@classmethod
|
||||
def get_object_spatial_props(cls, obj: bpy.types.Object) -> BIMObjectSpatialProperties:
|
||||
return obj.BIMObjectSpatialProperties
|
||||
|
||||
@classmethod
|
||||
def get_grid_props(cls) -> BIMGridProperties:
|
||||
return bpy.context.scene.BIMGridProperties
|
||||
|
||||
@classmethod
|
||||
def can_contain(cls, container: ifcopenshell.entity_instance, element_obj: Union[bpy.types.Object, None]) -> bool:
|
||||
if not (element := tool.Ifc.get_entity(element_obj)):
|
||||
@@ -81,7 +100,8 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def disable_editing(cls, obj: bpy.types.Object) -> None:
|
||||
obj.BIMObjectSpatialProperties.is_editing = False
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def duplicate_object_and_data(cls, obj: bpy.types.Object) -> bpy.types.Object:
|
||||
@@ -92,8 +112,9 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def enable_editing(cls, obj: bpy.types.Object) -> None:
|
||||
obj.BIMObjectSpatialProperties.is_editing = True
|
||||
obj.BIMObjectSpatialProperties.relating_container_object = None
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.is_editing = True
|
||||
props.relating_container_object = None
|
||||
|
||||
@classmethod
|
||||
def get_container(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
@@ -207,7 +228,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_container_elements_grouped_by_classification(cls, container: ifcopenshell.entity_instance) -> dict:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results = {}
|
||||
if props.should_include_children:
|
||||
elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True)
|
||||
@@ -254,7 +275,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_container_elements_grouped_by_type(cls, container: ifcopenshell.entity_instance) -> dict:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results: defaultdict[str, dict[int, Any]] = defaultdict(dict)
|
||||
if props.should_include_children:
|
||||
elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True)
|
||||
@@ -280,7 +301,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements(cls) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
props.elements.clear()
|
||||
if not (container := props.active_container):
|
||||
return
|
||||
@@ -295,7 +316,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_type(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results = cls.get_container_elements_grouped_by_type(container)
|
||||
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
@@ -350,7 +371,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_decomposition(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
expanded_ifc_ids = expanded_elements.get("IFC_ID", [])
|
||||
|
||||
@@ -381,7 +402,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_classification(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
expanded_classifications = expanded_elements.get("CLASSIFICATION", [])
|
||||
expanded_classifications_r = expanded_elements.get("CLASSIFICATION_R", [])
|
||||
@@ -445,7 +466,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def import_spatial_decomposition(cls) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
previous_container_index = props.active_container_index
|
||||
props.containers.clear()
|
||||
cls.contracted_containers = json.loads(props.contracted_containers)
|
||||
@@ -456,7 +477,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def import_spatial_element(cls, element: ifcopenshell.entity_instance, level_index: int) -> None:
|
||||
if not element.is_a("IfcProject") and not tool.Root.is_spatial_element(element):
|
||||
return
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
new = props.containers.add()
|
||||
new.ifc_class = element.is_a()
|
||||
new["name"] = element.Name or "Unnamed"
|
||||
@@ -485,28 +506,28 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_active_container(cls) -> Union[ifcopenshell.entity_instance, None]:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
if props.active_container_index < len(props.containers):
|
||||
container = tool.Ifc.get().by_id(props.containers[props.active_container_index].ifc_definition_id)
|
||||
return container
|
||||
|
||||
@classmethod
|
||||
def contract_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
contracted_containers = json.loads(props.contracted_containers)
|
||||
contracted_containers.append(container.id())
|
||||
props.contracted_containers = json.dumps(contracted_containers)
|
||||
|
||||
@classmethod
|
||||
def expand_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
contracted_containers = json.loads(props.contracted_containers)
|
||||
contracted_containers.remove(container.id())
|
||||
props.contracted_containers = json.dumps(contracted_containers)
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
if props.element_mode == "TYPE":
|
||||
cls.toggle_container_element_by_type(element_index, is_recursive)
|
||||
elif props.element_mode == "DECOMPOSITION":
|
||||
@@ -516,7 +537,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_type(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements)
|
||||
|
||||
element = props.elements[element_index]
|
||||
@@ -565,7 +586,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_decomposition(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
element = props.elements[element_index]
|
||||
expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements)
|
||||
expanded_elements_list: list[Union[str, int]] = expanded_elements.setdefault("IFC_ID", [])
|
||||
@@ -598,7 +619,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_classification(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements: dict[str, list[str]] = json.loads(props.expanded_elements)
|
||||
expanded_elements_list: list[str] = expanded_elements.setdefault("CLASSIFICATION", [])
|
||||
|
||||
@@ -679,7 +700,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_boundary_lines_from_context_visible_objects(cls) -> list[shapely.LineString]:
|
||||
props = props = tool.Model.get_model_props()
|
||||
props = tool.Model.get_model_props()
|
||||
calculation_rl = props.rl3
|
||||
container = tool.Root.get_default_container()
|
||||
container_obj = tool.Ifc.get_object(container)
|
||||
@@ -1154,8 +1175,8 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def set_default_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
from bonsai.bim.module.spatial.data import SpatialDecompositionData
|
||||
|
||||
assert bpy.context
|
||||
bpy.context.scene.BIMSpatialDecompositionProperties.default_container = container.id()
|
||||
props = cls.get_spatial_props()
|
||||
props.default_container = container.id()
|
||||
SpatialDecompositionData.data["default_container"] = SpatialDecompositionData.default_container()
|
||||
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
@@ -1212,16 +1233,16 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def set_target_container_as_default(cls) -> None:
|
||||
if (
|
||||
(container := tool.Root.get_default_container())
|
||||
and (obj := tool.Ifc.get_object(container))
|
||||
and bpy.context.active_object
|
||||
and (container_obj := tool.Ifc.get_object(container))
|
||||
and (obj := bpy.context.active_object)
|
||||
):
|
||||
props = bpy.context.active_object.BIMObjectSpatialProperties
|
||||
props.container_obj = obj
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.container_obj = container_obj
|
||||
|
||||
@classmethod
|
||||
def get_filtered_elements(cls, should_filter: bool = True) -> Iterable[ifcopenshell.entity_instance]:
|
||||
ifc_file = tool.Ifc.get()
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
container = ifc_file.by_id(props.active_container.ifc_definition_id)
|
||||
element_filter = props.element_filter
|
||||
active_element = props.active_element
|
||||
|
||||
@@ -383,7 +383,8 @@ class TestUsingArrays(NewFile):
|
||||
|
||||
bpy.ops.mesh.primitive_cube_add()
|
||||
obj = bpy.context.active_object
|
||||
bpy.context.scene.BIMRootProperties.ifc_product = "IfcElement"
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.ifc_product = "IfcElement"
|
||||
bpy.ops.bim.assign_class(ifc_class="IfcActuator", predefined_type="ELECTRICACTUATOR", userdefined_type="")
|
||||
|
||||
bpy.ops.bim.add_array()
|
||||
@@ -520,7 +521,7 @@ class TestApplyIfcMaterialChanges(NewFile):
|
||||
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||
with_opening = bpy.context.active_object
|
||||
with_opening.name = "With Opening"
|
||||
props = bpy.context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
props.representation_obj = with_opening
|
||||
bpy.ops.bim.add_element(ifc_product="IfcFeatureElement", ifc_class="IfcOpeningElement")
|
||||
|
||||
|
||||
@@ -97,7 +97,8 @@ class TestSetContext(NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
subject.set_context(context)
|
||||
assert bpy.context.scene.BIMRootProperties.contexts == str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
assert rprops.contexts == str(context.id())
|
||||
|
||||
|
||||
class TestSetDefaultContext(NewFile):
|
||||
@@ -115,7 +116,8 @@ class TestSetDefaultContext(NewFile):
|
||||
target_view="MODEL_VIEW",
|
||||
)
|
||||
subject.set_default_context()
|
||||
assert bpy.context.scene.BIMRootProperties.contexts == str(body.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
assert rprops.contexts == str(body.id())
|
||||
|
||||
|
||||
class TestSetDefaultModelingDimensions(NewFile):
|
||||
|
||||
@@ -191,8 +191,10 @@ class TestReassignClass(NewFile):
|
||||
slabs = [tool.Ifc.get_object(e) for e in ifc_file.by_type("IfcSlab")]
|
||||
assert len(slabs) == 3
|
||||
tool.Blender.set_objects_selection(context, slabs[0], (slabs[1],))
|
||||
context.scene.BIMRootProperties.ifc_product = "IfcElement"
|
||||
context.scene.BIMRootProperties.ifc_class = "IfcWall"
|
||||
|
||||
props = tool.Root.get_root_props()
|
||||
props.ifc_product = "IfcElement"
|
||||
props.ifc_class = "IfcWall"
|
||||
bpy.ops.bim.reassign_class()
|
||||
|
||||
assert len(ifc_file.by_type("IfcWall")) == 3
|
||||
|
||||
@@ -129,7 +129,8 @@ class TestDisableEditing(NewFile):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
subject.disable_editing(obj)
|
||||
assert obj.BIMObjectSpatialProperties.is_editing is False
|
||||
props = tool.Spatial.get_object_spatial_props(obj)
|
||||
assert props.is_editing is False
|
||||
|
||||
|
||||
class TestDuplicateObjectAndData(NewFile):
|
||||
@@ -148,7 +149,8 @@ class TestEnableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
assert obj.BIMObjectSpatialProperties.is_editing is True
|
||||
props = tool.Spatial.get_object_spatial_props(obj)
|
||||
assert props.is_editing is True
|
||||
|
||||
|
||||
class TestGetContainer(NewFile):
|
||||
|
||||
@@ -28,11 +28,8 @@ def remove_cost_item_quantity(
|
||||
removed.
|
||||
|
||||
:param cost_item: The IfcCostItem that the quantity is assigned to
|
||||
:type cost_item: ifcopenshell.entity_instance
|
||||
:param physical_quantity: The IfcPhysicalQuantity to remove
|
||||
:type physical_quantity: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -46,11 +43,9 @@ def remove_cost_item_quantity(
|
||||
ifcopenshell.api.cost.remove_cost_item(model,
|
||||
cost_item=item, physical_quantity=quantity)
|
||||
"""
|
||||
settings = {"cost_item": cost_item, "physical_quantity": physical_quantity}
|
||||
|
||||
if len(file.get_inverse(settings["physical_quantity"])) == 1:
|
||||
file.remove(settings["physical_quantity"])
|
||||
if len(file.get_inverse(physical_quantity)) == 1:
|
||||
file.remove(physical_quantity)
|
||||
return
|
||||
quantities = list(settings["cost_item"].CostQuantities or [])
|
||||
quantities.remove(settings["physical_quantity"])
|
||||
settings["cost_item"].CostQuantities = quantities
|
||||
quantities = list(cost_item.CostQuantities or [])
|
||||
quantities.remove(physical_quantity)
|
||||
cost_item.CostQuantities = quantities
|
||||
|
||||
@@ -28,11 +28,8 @@ def remove_cost_value(
|
||||
|
||||
:param parent: The IfcCostItem, IfcConstructionResource, or IfcCostValue
|
||||
that the IfcCostValue is assigned to.
|
||||
:type parent: ifcopenshell.entity_instance
|
||||
:param cost_value: The IfcCostValue that you want to remove
|
||||
:type parent: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -48,20 +45,18 @@ def remove_cost_value(
|
||||
|
||||
ifcopenshell.api.cost.remove_cost_value(model, parent=item, cost_value=value)
|
||||
"""
|
||||
settings = {"parent": parent, "cost_value": cost_value}
|
||||
|
||||
if len(file.get_inverse(settings["cost_value"])) == 1:
|
||||
file.remove(settings["cost_value"])
|
||||
if len(file.get_inverse(cost_value)) == 1:
|
||||
file.remove(cost_value)
|
||||
# TODO deep purge
|
||||
elif settings["parent"].is_a("IfcCostItem"):
|
||||
values = list(settings["parent"].CostValues)
|
||||
values.remove(settings["cost_value"])
|
||||
settings["parent"].CostValues = values if values else None
|
||||
elif settings["parent"].is_a("IfcConstructionResource"):
|
||||
values = list(settings["parent"].BaseCosts)
|
||||
values.remove(settings["cost_value"])
|
||||
settings["parent"].BaseCosts = values if values else None
|
||||
elif settings["parent"].is_a("IfcCostValue"):
|
||||
components = list(settings["parent"].Components)
|
||||
components.remove(settings["cost_value"])
|
||||
settings["parent"].Components = components if components else None
|
||||
elif parent.is_a("IfcCostItem"):
|
||||
values = list(parent.CostValues)
|
||||
values.remove(cost_value)
|
||||
parent.CostValues = values if values else None
|
||||
elif parent.is_a("IfcConstructionResource"):
|
||||
values = list(parent.BaseCosts)
|
||||
values.remove(cost_value)
|
||||
parent.BaseCosts = values if values else None
|
||||
elif parent.is_a("IfcCostValue"):
|
||||
components = list(parent.Components)
|
||||
components.remove(cost_value)
|
||||
parent.Components = components if components else None
|
||||
|
||||
@@ -23,9 +23,7 @@ def remove_grid_axis(file: ifcopenshell.file, axis: ifcopenshell.entity_instance
|
||||
"""Removes a grid axis from a grid
|
||||
|
||||
:param axis: The IfcGridAxis you want to remove.
|
||||
:type axis: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -92,19 +92,17 @@ def assign_profile(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"material_profile": material_profile, "profile": profile}
|
||||
return usecase.execute()
|
||||
return usecase.execute(material_profile, profile)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self) -> None:
|
||||
def execute(self, material_profile: ifcopenshell.entity_instance, profile: ifcopenshell.entity_instance) -> None:
|
||||
# TODO: handle composite profiles
|
||||
old_profile = self.settings["material_profile"].Profile
|
||||
self.settings["material_profile"].Profile = self.settings["profile"]
|
||||
for profile_set in self.settings["material_profile"].ToMaterialProfileSet:
|
||||
old_profile = material_profile.Profile
|
||||
material_profile.Profile = profile
|
||||
for profile_set in material_profile.ToMaterialProfileSet:
|
||||
for inverse in self.file.get_inverse(profile_set):
|
||||
if not inverse.is_a("IfcMaterialProfileSetUsage"):
|
||||
continue
|
||||
@@ -113,20 +111,20 @@ class Usecase:
|
||||
if not rel.is_a("IfcRelAssociatesMaterial"):
|
||||
continue
|
||||
for element in rel.RelatedObjects:
|
||||
self.change_profile(element)
|
||||
self.change_profile(element, profile)
|
||||
else:
|
||||
for rel in inverse.AssociatedTo:
|
||||
for element in rel.RelatedObjects:
|
||||
self.change_profile(element)
|
||||
self.change_profile(element, profile)
|
||||
|
||||
if old_profile and len(self.file.get_inverse(old_profile)) == 0:
|
||||
# TODO: check remove deep
|
||||
self.file.remove(old_profile)
|
||||
|
||||
def change_profile(self, element: ifcopenshell.entity_instance) -> None:
|
||||
def change_profile(self, element: ifcopenshell.entity_instance, profile: ifcopenshell.entity_instance) -> None:
|
||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
if not representation:
|
||||
return
|
||||
for subelement in self.file.traverse(representation):
|
||||
if subelement.is_a("IfcSweptAreaSolid"):
|
||||
subelement.SweptArea = self.settings["profile"]
|
||||
subelement.SweptArea = profile
|
||||
|
||||
@@ -27,9 +27,7 @@ def remove_organisation(file: ifcopenshell.file, organisation: ifcopenshell.enti
|
||||
removed.
|
||||
|
||||
:param organisation: The IfcOrganization to remove
|
||||
:type organisation: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -39,31 +37,29 @@ def remove_organisation(file: ifcopenshell.file, organisation: ifcopenshell.enti
|
||||
identification="AWB", name="Architects Without Ballpens")
|
||||
ifcopenshell.api.owner.remove_organisation(model, organisation=organisation)
|
||||
"""
|
||||
settings = {"organisation": organisation}
|
||||
|
||||
for role in settings["organisation"].Roles or []:
|
||||
for role in organisation.Roles or []:
|
||||
if len(file.get_inverse(role)) == 1:
|
||||
ifcopenshell.api.owner.remove_role(file, role=role)
|
||||
for address in settings["organisation"].Addresses or []:
|
||||
for address in organisation.Addresses or []:
|
||||
if len(file.get_inverse(address)) == 1:
|
||||
ifcopenshell.api.owner.remove_address(file, address=address)
|
||||
for inverse in file.get_inverse(settings["organisation"]):
|
||||
for inverse in file.get_inverse(organisation):
|
||||
if inverse.is_a("IfcOrganizationRelationship"):
|
||||
if inverse.RelatingOrganization == settings["organisation"]:
|
||||
if inverse.RelatingOrganization == organisation:
|
||||
file.remove(inverse)
|
||||
elif inverse.RelatedOrganizations == (settings["organisation"],):
|
||||
elif inverse.RelatedOrganizations == (organisation,):
|
||||
file.remove(inverse)
|
||||
elif inverse.is_a("IfcDocumentInformation"):
|
||||
if inverse.Editors == (settings["organisation"],):
|
||||
if inverse.Editors == (organisation,):
|
||||
inverse.Editors = None
|
||||
elif inverse.is_a("IfcPersonAndOrganization"):
|
||||
ifcopenshell.api.owner.remove_person_and_organisation(file, person_and_organisation=inverse)
|
||||
elif inverse.is_a("IfcActor"):
|
||||
ifcopenshell.api.root.remove_product(file, product=inverse)
|
||||
elif inverse.is_a("IfcResourceLevelRelationship") and not inverse.is_a("IfcOrganizationRelationship"):
|
||||
if inverse.RelatedResourceObjects == (settings["organisation"],):
|
||||
if inverse.RelatedResourceObjects == (organisation,):
|
||||
file.remove(inverse)
|
||||
elif inverse.is_a("IfcApplication"):
|
||||
ifcopenshell.api.owner.remove_application(file, application=inverse)
|
||||
|
||||
file.remove(settings["organisation"])
|
||||
file.remove(organisation)
|
||||
|
||||
@@ -29,9 +29,7 @@ def remove_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance)
|
||||
the only responsile person for them.
|
||||
|
||||
:param person: The IfcPerson to remove
|
||||
:type person: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -41,31 +39,30 @@ def remove_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance)
|
||||
identification="bobthebuilder", family_name="Thebuilder", given_name="Bob")
|
||||
ifcopenshell.api.owner.remove_person(model, person=person)
|
||||
"""
|
||||
settings = {"person": person}
|
||||
|
||||
for role in settings["person"].Roles or []:
|
||||
for role in person.Roles or []:
|
||||
if len(file.get_inverse(role)) == 1:
|
||||
ifcopenshell.api.owner.remove_role(file, role=role)
|
||||
for address in settings["person"].Addresses or []:
|
||||
for address in person.Addresses or []:
|
||||
if len(file.get_inverse(address)) == 1:
|
||||
ifcopenshell.api.owner.remove_address(file, address=address)
|
||||
for inverse in file.get_inverse(settings["person"]):
|
||||
for inverse in file.get_inverse(person):
|
||||
if inverse.is_a("IfcWorkControl"):
|
||||
if inverse.Creators == (settings["person"],):
|
||||
if inverse.Creators == (person,):
|
||||
inverse.Creators = None
|
||||
elif inverse.is_a("IfcInventory"):
|
||||
if inverse.ResponsiblePersons == (settings["person"],):
|
||||
if inverse.ResponsiblePersons == (person,):
|
||||
# in IFC2X3 ResponsiblePersons is not optional and without it IfcInventory is not valid
|
||||
if file.schema == "IFC2X3":
|
||||
ifcopenshell.api.root.remove_product(file, product=inverse)
|
||||
elif inverse.is_a("IfcDocumentInformation"):
|
||||
if inverse.Editors == (settings["person"],):
|
||||
if inverse.Editors == (person,):
|
||||
inverse.Editors = None
|
||||
elif inverse.is_a("IfcPersonAndOrganization"):
|
||||
ifcopenshell.api.owner.remove_person_and_organisation(file, person_and_organisation=inverse)
|
||||
elif inverse.is_a("IfcActor"):
|
||||
ifcopenshell.api.root.remove_product(file, product=inverse)
|
||||
elif inverse.is_a("IfcResourceLevelRelationship"):
|
||||
if inverse.RelatedResourceObjects == (settings["person"],):
|
||||
if inverse.RelatedResourceObjects == (person,):
|
||||
file.remove(inverse)
|
||||
file.remove(settings["person"])
|
||||
file.remove(person)
|
||||
|
||||
@@ -80,8 +80,8 @@ def assign_lag_time(
|
||||
# for whatever reason.
|
||||
ifcopenshell.api.sequence.assign_lag_time(model, rel_sequence=sequence, lag_value="P1D")
|
||||
"""
|
||||
lag_value = file.create_entity("IfcDuration", ifcopenshell.util.date.datetime2ifc(lag_value, "IfcDuration"))
|
||||
lag_time = file.create_entity("IfcLagTime", DurationType=duration_type, LagValue=lag_value)
|
||||
duration = file.create_entity("IfcDuration", ifcopenshell.util.date.datetime2ifc(lag_value, "IfcDuration"))
|
||||
lag_time = file.create_entity("IfcLagTime", DurationType=duration_type, LagValue=duration)
|
||||
if rel_sequence.is_a("IfcRelSequence"):
|
||||
if rel_sequence.TimeLag and len(file.get_inverse(rel_sequence.TimeLag)) == 1:
|
||||
file.remove(rel_sequence.TimeLag)
|
||||
|
||||
@@ -25,9 +25,7 @@ def unassign_lag_time(file: ifcopenshell.file, rel_sequence: ifcopenshell.entity
|
||||
The schedule is cascaded afterwards.
|
||||
|
||||
:param rel_sequence: The sequence to remove the lag time from.
|
||||
:type rel_sequence: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -57,12 +55,8 @@ def unassign_lag_time(file: ifcopenshell.file, rel_sequence: ifcopenshell.entity
|
||||
# What if you didn't?
|
||||
ifcopenshell.api.sequence.unassign_lag_time(model, rel_sequence=sequence)
|
||||
"""
|
||||
settings = {
|
||||
"rel_sequence": rel_sequence,
|
||||
}
|
||||
|
||||
if len(file.get_inverse(settings["rel_sequence"].TimeLag)) == 1:
|
||||
file.remove(settings["rel_sequence"].TimeLag)
|
||||
if len(file.get_inverse(rel_sequence.TimeLag)) == 1:
|
||||
file.remove(rel_sequence.TimeLag)
|
||||
else:
|
||||
settings["rel_sequence"].TimeLag = None
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=settings["rel_sequence"].RelatedProcess)
|
||||
rel_sequence.TimeLag = None
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=rel_sequence.RelatedProcess)
|
||||
|
||||
+3
-7
@@ -29,18 +29,14 @@ def remove_structural_analysis_model(
|
||||
|
||||
:param structural_analysis_model: The IfcStructuralAnalysisModel to
|
||||
remove.
|
||||
:type structural_analysis_model: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"structural_analysis_model": structural_analysis_model}
|
||||
|
||||
for rel in settings["structural_analysis_model"].IsGroupedBy or []:
|
||||
for rel in structural_analysis_model.IsGroupedBy or []:
|
||||
history = rel.OwnerHistory
|
||||
file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
history = settings["structural_analysis_model"].OwnerHistory
|
||||
file.remove(settings["structural_analysis_model"])
|
||||
history = structural_analysis_model.OwnerHistory
|
||||
file.remove(structural_analysis_model)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
+9
-11
@@ -28,23 +28,21 @@ def remove_structural_boundary_condition(
|
||||
|
||||
:param connection: The IfcStructuralConnection to remove the condition
|
||||
from. If omitted, it is assumed to be an orphaned condition.
|
||||
:type connection: ifcopenshell.entity_instance,optional
|
||||
:param boundary_condition: The IfcBoundaryCondition to remove.
|
||||
:type boundary_condition: ifcopenshell.entity_instance, optional.
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"connection": connection, "boundary_condition": boundary_condition}
|
||||
|
||||
if settings["connection"]:
|
||||
if connection:
|
||||
# remove boundary condition from a connection
|
||||
if not settings["connection"].AppliedCondition:
|
||||
if not connection.AppliedCondition:
|
||||
return
|
||||
if len(file.get_inverse(settings["connection"].AppliedCondition)) == 1:
|
||||
file.remove(settings["connection"].AppliedCondition)
|
||||
settings["connection"].AppliedCondition = None
|
||||
applied_condition = connection.AppliedCondition
|
||||
if file.get_total_inverses(applied_condition) == 1:
|
||||
file.remove(applied_condition)
|
||||
connection.AppliedCondition = None
|
||||
else:
|
||||
assert boundary_condition, "Either connection or boundary_condition must be provided."
|
||||
# remove the boundary condition
|
||||
for conn in file.get_inverse(settings["boundary_condition"]):
|
||||
for conn in file.get_inverse(boundary_condition):
|
||||
conn.AppliedCondition = None
|
||||
file.remove(settings["boundary_condition"])
|
||||
file.remove(boundary_condition)
|
||||
|
||||
@@ -22,10 +22,6 @@ def remove_structural_load(file: ifcopenshell.file, structural_load: ifcopenshel
|
||||
"""Removes a structural load
|
||||
|
||||
:param structural_load: The IfcStructuralLoad to remove.
|
||||
:type structural_load: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"structural_load": structural_load}
|
||||
|
||||
file.remove(settings["structural_load"])
|
||||
file.remove(structural_load)
|
||||
|
||||
@@ -25,18 +25,14 @@ def remove_structural_load_case(file: ifcopenshell.file, load_case: ifcopenshell
|
||||
"""Removes a structural load case
|
||||
|
||||
:param load_case: The IfcStructuralLoadCase to remove.
|
||||
:type load_case: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"load_case": load_case}
|
||||
|
||||
# TODO: do a deep purge
|
||||
for rel in settings["load_case"].IsGroupedBy or []:
|
||||
for rel in load_case.IsGroupedBy or []:
|
||||
history = rel.OwnerHistory
|
||||
file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
history = settings["load_case"].OwnerHistory
|
||||
file.remove(settings["load_case"])
|
||||
history = load_case.OwnerHistory
|
||||
file.remove(load_case)
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
@@ -25,20 +25,16 @@ def remove_structural_load_group(file: ifcopenshell.file, load_group: ifcopenshe
|
||||
"""Removes a structural load group
|
||||
|
||||
:param load_group: The IfcStructuralLoadGroup to remove.
|
||||
:type load_group: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"load_group": load_group}
|
||||
|
||||
# TODO: do a deep purge
|
||||
for inverse in file.get_inverse(settings["load_group"]):
|
||||
for inverse in file.get_inverse(load_group):
|
||||
if inverse.is_a("IfcRelAssignsToGroup") and len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
history = settings["load_group"].OwnerHistory
|
||||
file.remove(settings["load_group"])
|
||||
history = load_group.OwnerHistory
|
||||
file.remove(load_group)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
@@ -835,6 +835,7 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str = "
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.api.georeference
|
||||
import ifcopenshell.api.unit
|
||||
|
||||
prefix = get_prefix(target_units)
|
||||
si_unit = get_unit_name(target_units)
|
||||
|
||||
Reference in New Issue
Block a user