mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
typing
This commit is contained in:
@@ -228,7 +228,7 @@ def refresh_ui_data():
|
||||
|
||||
|
||||
@persistent
|
||||
def loadIfcStore(scene):
|
||||
def loadIfcStore(scene: bpy.types.Scene) -> None:
|
||||
IfcStore.purge()
|
||||
refresh_ui_data()
|
||||
if not tool.Ifc.get():
|
||||
@@ -238,19 +238,21 @@ def loadIfcStore(scene):
|
||||
|
||||
|
||||
@persistent
|
||||
def undo_post(scene):
|
||||
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
|
||||
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
|
||||
IfcStore.undo(until_key=bpy.context.scene.BIMProperties.last_transaction)
|
||||
def undo_post(scene: bpy.types.Scene) -> None:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if IfcStore.last_transaction != props.last_transaction:
|
||||
IfcStore.last_transaction = props.last_transaction
|
||||
IfcStore.undo(until_key=props.last_transaction)
|
||||
refresh_ui_data()
|
||||
tool.Ifc.rebuild_element_maps()
|
||||
|
||||
|
||||
@persistent
|
||||
def redo_post(scene):
|
||||
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
|
||||
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
|
||||
IfcStore.redo(until_key=bpy.context.scene.BIMProperties.last_transaction)
|
||||
def redo_post(scene: bpy.types.Scene) -> None:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if IfcStore.last_transaction != props.last_transaction:
|
||||
IfcStore.last_transaction = props.last_transaction
|
||||
IfcStore.redo(until_key=props.last_transaction)
|
||||
refresh_ui_data()
|
||||
tool.Ifc.rebuild_element_maps()
|
||||
|
||||
@@ -283,7 +285,7 @@ def get_user(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None
|
||||
return pao
|
||||
|
||||
|
||||
def viewport_shading_changed_callback(area):
|
||||
def viewport_shading_changed_callback(area: bpy.types.Area) -> None:
|
||||
shading = area.spaces.active.shading.type
|
||||
if shading == "RENDERED":
|
||||
bpy.context.scene.BIMStylesProperties.active_style_type = "External"
|
||||
@@ -341,7 +343,8 @@ def load_post(scene):
|
||||
tool.Blender.setup_tabs()
|
||||
|
||||
if tool.Ifc.get() and bpy.data.is_saved:
|
||||
bpy.context.scene.BIMProperties.has_blend_warning = True
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.has_blend_warning = True
|
||||
|
||||
# Bonsai overlays
|
||||
georeference_props = tool.Georeference.get_georeference_props()
|
||||
|
||||
@@ -32,6 +32,7 @@ from typing import Optional, Callable, Any, Union, Iterable, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
import bonsai.bim.prop
|
||||
from bonsai.bim.prop import Attribute
|
||||
from bonsai.bim.module.search.prop import BIMFilterGroup
|
||||
|
||||
# ImportCallback return values:
|
||||
# - None - property should be imported by default workflow
|
||||
@@ -372,11 +373,16 @@ def convert_property_group_from_si(property_group: bpy.types.PropertyGroup, skip
|
||||
setattr(property_group, prop_name, prop_value)
|
||||
|
||||
|
||||
def draw_filter(layout: bpy.types.UILayout, filter_groups, data, module: str) -> None:
|
||||
def draw_filter(
|
||||
layout: bpy.types.UILayout,
|
||||
filter_groups: bpy.types.bpy_prop_collection_idprop[BIMFilterGroup],
|
||||
data,
|
||||
module: str,
|
||||
) -> None:
|
||||
if not data.is_loaded:
|
||||
data.load()
|
||||
|
||||
sprops = bpy.context.scene.BIMSearchProperties
|
||||
sprops = tool.Search.get_search_props()
|
||||
|
||||
if tool.Ifc.get():
|
||||
row = layout.row(align=True)
|
||||
|
||||
@@ -105,7 +105,8 @@ class IfcStore:
|
||||
@staticmethod
|
||||
def get_file():
|
||||
if IfcStore.file is None:
|
||||
IfcStore.path = cast(str, bpy.context.scene.BIMProperties.ifc_file)
|
||||
props = tool.Blender.get_bim_props()
|
||||
IfcStore.path = props.ifc_file
|
||||
# Interpret relative paths as relative to .blend file.
|
||||
if IfcStore.path and not os.path.isabs(IfcStore.path):
|
||||
IfcStore.path = os.path.abspath(os.path.join(bpy.path.abspath("//"), IfcStore.path))
|
||||
@@ -119,10 +120,11 @@ class IfcStore:
|
||||
@staticmethod
|
||||
def get_cache():
|
||||
if IfcStore.cache is None and IfcStore.path:
|
||||
props = tool.Blender.get_bim_props()
|
||||
ifc_key = IfcStore.path + IfcStore.file.wrapped_data.header.file_name.time_stamp
|
||||
ifc_hash = hashlib.md5(ifc_key.encode("utf-8")).hexdigest()
|
||||
os.makedirs(bpy.context.scene.BIMProperties.cache_dir, exist_ok=True)
|
||||
IfcStore.cache_path = os.path.join(bpy.context.scene.BIMProperties.cache_dir, f"{ifc_hash}.h5")
|
||||
os.makedirs(props.cache_dir, exist_ok=True)
|
||||
IfcStore.cache_path = os.path.join(props.cache_dir, f"{ifc_hash}.h5")
|
||||
cache_path = Path(IfcStore.cache_path)
|
||||
cache_settings = ifcopenshell.geom.settings()
|
||||
serializer_settings = ifcopenshell.geom.serializer_settings()
|
||||
@@ -162,7 +164,8 @@ class IfcStore:
|
||||
assert IfcStore.file
|
||||
ifc_key = IfcStore.path + IfcStore.file.wrapped_data.header.file_name.time_stamp
|
||||
ifc_hash = hashlib.md5(ifc_key.encode("utf-8")).hexdigest()
|
||||
new_cache_path = os.path.join(bpy.context.scene.BIMProperties.cache_dir, f"{ifc_hash}.h5")
|
||||
props = tool.Blender.get_bim_props()
|
||||
new_cache_path = os.path.join(props.cache_dir, f"{ifc_hash}.h5")
|
||||
IfcStore.cache = None
|
||||
try:
|
||||
shutil.move(IfcStore.cache_path, new_cache_path)
|
||||
@@ -414,7 +417,8 @@ class IfcStore:
|
||||
method: Literal["EXECUTE", "INVOKE", "MODAL"] = "EXECUTE",
|
||||
) -> set[str]:
|
||||
bonsai.last_actions.append({"type": "operator", "name": operator.bl_idname})
|
||||
bpy.context.scene.BIMProperties.is_dirty = True
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.is_dirty = True
|
||||
# Modals don't nest, and Blender handles the loop that continuously calls modal()
|
||||
is_top_level_operator = not bool(IfcStore.current_transaction) or (method == "MODAL")
|
||||
|
||||
@@ -493,7 +497,8 @@ class IfcStore:
|
||||
) -> None:
|
||||
key = getattr(operator, "transaction_key", None)
|
||||
data = getattr(operator, "transaction_data", None)
|
||||
bpy.context.scene.BIMProperties.last_transaction = key
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.last_transaction = key
|
||||
IfcStore.last_transaction = key
|
||||
rollback = rollback or getattr(operator, "rollback", lambda data: True)
|
||||
commit = commit or getattr(operator, "commit", lambda data: True)
|
||||
|
||||
@@ -879,17 +879,19 @@ class IfcImporter:
|
||||
|
||||
def load_file(self):
|
||||
self.ifc_import_settings.logger.info("loading file %s", self.ifc_import_settings.input_file)
|
||||
if not bpy.context.scene.BIMProperties.ifc_file:
|
||||
bpy.context.scene.BIMProperties.ifc_file = self.ifc_import_settings.input_file
|
||||
props = tool.Blender.get_bim_props()
|
||||
if not props.ifc_file:
|
||||
props.ifc_file = self.ifc_import_settings.input_file
|
||||
self.file = tool.Ifc.get()
|
||||
|
||||
def calculate_unit_scale(self):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
tool.Loader.set_unit_scale(self.unit_scale)
|
||||
|
||||
def set_units(self):
|
||||
def set_units(self) -> None:
|
||||
if not (assignment := self.file.by_type("IfcProject")[0].UnitsInContext):
|
||||
return # Geometry is optional in IFC
|
||||
props = tool.Blender.get_bim_props()
|
||||
for unit in assignment.Units:
|
||||
if unit.is_a("IfcNamedUnit") and unit.UnitType == "LENGTHUNIT":
|
||||
if unit.is_a("IfcSIUnit"):
|
||||
@@ -909,19 +911,19 @@ class IfcImporter:
|
||||
elif unit.is_a("IfcNamedUnit") and unit.UnitType == "AREAUNIT":
|
||||
name = unit.Name if unit.is_a("IfcSIUnit") else unit.Name.lower()
|
||||
try:
|
||||
bpy.context.scene.BIMProperties.area_unit = "{}{}".format(
|
||||
props.area_unit = "{}{}".format(
|
||||
unit.Prefix + "/" if hasattr(unit, "Prefix") and unit.Prefix else "", name
|
||||
)
|
||||
except: # Probably an invalid unit.
|
||||
bpy.context.scene.BIMProperties.area_unit = "SQUARE_METRE"
|
||||
props.area_unit = "SQUARE_METRE"
|
||||
elif unit.is_a("IfcNamedUnit") and unit.UnitType == "VOLUMEUNIT":
|
||||
name = unit.Name if unit.is_a("IfcSIUnit") else unit.Name.lower()
|
||||
try:
|
||||
bpy.context.scene.BIMProperties.volume_unit = "{}{}".format(
|
||||
props.volume_unit = "{}{}".format(
|
||||
unit.Prefix + "/" if hasattr(unit, "Prefix") and unit.Prefix else "", name
|
||||
)
|
||||
except: # Probably an invalid unit.
|
||||
bpy.context.scene.BIMProperties.volume_unit = "CUBIC_METRE"
|
||||
props.volume_unit = "CUBIC_METRE"
|
||||
|
||||
def create_project(self):
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
|
||||
@@ -122,15 +122,16 @@ class AuginCreateNewModel(bpy.types.Operator):
|
||||
context.scene.render.image_settings.file_format = old_file_format
|
||||
context.scene.render.filepath = old_filepath
|
||||
|
||||
client.upload_file(context.scene.BIMProperties.ifc_file, result["s3_bucket"], result["model_path"])
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
client.upload_file(bim_props.ifc_file, result["s3_bucket"], result["model_path"])
|
||||
client.upload_file(thumb_path, result["s3_bucket"], result["thumb_path"])
|
||||
|
||||
# Notify done
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/files_uploaded"
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
"ifc_filesize": os.path.getsize(context.scene.BIMProperties.ifc_file),
|
||||
"model_filesize": os.path.getsize(context.scene.BIMProperties.ifc_file),
|
||||
"ifc_filesize": os.path.getsize(bim_props.ifc_file),
|
||||
"model_filesize": os.path.getsize(bim_props.ifc_file),
|
||||
"thumb_filesize": os.path.getsize(thumb_path),
|
||||
"model_upload_path": result["model_path"],
|
||||
"thumb_upload_path": result["thumb_path"],
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy.types
|
||||
import bonsai.tool as tool
|
||||
|
||||
|
||||
class BIM_PT_augin(bpy.types.Panel):
|
||||
@@ -47,7 +48,8 @@ class BIM_PT_augin(bpy.types.Panel):
|
||||
row = layout.row()
|
||||
row.label(text="Logged in as " + props.username)
|
||||
|
||||
if not context.scene.BIMProperties.ifc_file:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if not bim_props.ifc_file:
|
||||
row = layout.row()
|
||||
row.label(text="No IFC Found")
|
||||
return
|
||||
|
||||
@@ -321,8 +321,9 @@ class SelectIfcClashResults(bpy.types.Operator):
|
||||
|
||||
ifc_file = ""
|
||||
for scene in obj.users_scene:
|
||||
if scene.BIMProperties.ifc_file:
|
||||
ifc_file = scene.BIMProperties.ifc_file
|
||||
bim_props = tool.Blender.get_bim_props(scene)
|
||||
if bim_props.ifc_file:
|
||||
ifc_file = bim_props.ifc_file
|
||||
if scene.library:
|
||||
break
|
||||
|
||||
|
||||
@@ -106,7 +106,8 @@ class ConvertToBlender(bpy.types.Operator):
|
||||
if material.library:
|
||||
continue
|
||||
tool.Ifc.unlink(obj=material)
|
||||
context.scene.BIMProperties.ifc_file = ""
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bim_props.ifc_file = ""
|
||||
tool.Debug.get_debug_props().attributes.clear()
|
||||
IfcStore.purge()
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
@@ -160,7 +161,8 @@ class ProfileImportIFC(bpy.types.Operator):
|
||||
if not tool.Ifc.get():
|
||||
cls.poll_message_set("No IFC file loaded.")
|
||||
return False
|
||||
if not context.scene.BIMProperties.ifc_file:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if not bim_props.ifc_file:
|
||||
cls.poll_message_set("Current IFC file is not saved.")
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -34,9 +34,10 @@ class BIM_PT_debug(Panel):
|
||||
layout = self.layout
|
||||
|
||||
props = tool.Debug.get_debug_props()
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.BIMProperties, "ifc_file", text="")
|
||||
row.prop(bim_props, "ifc_file", text="")
|
||||
row.operator("bim.validate_ifc_file", icon="CHECKMARK", text="")
|
||||
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@ class VisualiseDiff(bpy.types.Operator):
|
||||
|
||||
ifc_file = ""
|
||||
for scene in obj.users_scene:
|
||||
if scene.BIMProperties.ifc_file:
|
||||
ifc_file = scene.BIMProperties.ifc_file
|
||||
bim_props = tool.Blender.get_bim_props(scene)
|
||||
if bim_props.ifc_file:
|
||||
ifc_file = bim_props.ifc_file
|
||||
if scene.library:
|
||||
break
|
||||
|
||||
@@ -257,8 +258,9 @@ class SelectDiffObjects(bpy.types.Operator):
|
||||
|
||||
ifc_file = ""
|
||||
for scene in obj.users_scene:
|
||||
if scene.BIMProperties.ifc_file:
|
||||
ifc_file = scene.BIMProperties.ifc_file
|
||||
bim_props = tool.Blender.get_bim_props(scene)
|
||||
if bim_props.ifc_file:
|
||||
ifc_file = bim_props.ifc_file
|
||||
if scene.library:
|
||||
break
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class DocumentData:
|
||||
|
||||
@classmethod
|
||||
def parent_document(cls):
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
if len(props.breadcrumbs):
|
||||
parent = tool.Ifc.get().by_id(int(props.breadcrumbs[-1].name))
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
|
||||
@@ -115,7 +115,7 @@ class EditDocument(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
core.edit_document(tool.Ifc, tool.Document, document=tool.Ifc.get().by_id(props.active_document_id))
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
def update_document_name(self: "Document", context: bpy.types.Context) -> None:
|
||||
@@ -57,6 +58,11 @@ class Document(PropertyGroup):
|
||||
)
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
identification: str
|
||||
is_information: bool
|
||||
ifc_definition_id: int
|
||||
|
||||
|
||||
class BIMDocumentProperties(PropertyGroup):
|
||||
document_attributes: CollectionProperty(name="Document Attributes", type=Attribute)
|
||||
@@ -65,3 +71,11 @@ class BIMDocumentProperties(PropertyGroup):
|
||||
breadcrumbs: CollectionProperty(name="Breadcrumbs", type=StrProperty)
|
||||
active_document_index: IntProperty(name="Active Document Index")
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
document_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
|
||||
active_document_id: int
|
||||
documents: bpy.types.bpy_prop_collection_idprop[Document]
|
||||
breadcrumbs: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
active_document_index: int
|
||||
is_editing: bool
|
||||
|
||||
@@ -39,7 +39,7 @@ class BIM_PT_documents(Panel):
|
||||
if not DocumentData.is_loaded:
|
||||
DocumentData.load()
|
||||
|
||||
self.props = context.scene.BIMDocumentProperties
|
||||
self.props = tool.Document.get_document_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Documents Found".format(DocumentData.data["total_information"]), icon="FILE")
|
||||
@@ -102,7 +102,7 @@ class BIM_PT_object_documents(Panel):
|
||||
|
||||
obj = context.active_object
|
||||
self.oprops = obj.BIMObjectProperties
|
||||
self.props = context.scene.BIMDocumentProperties
|
||||
self.props = tool.Document.get_document_props()
|
||||
self.file = tool.Ifc.get()
|
||||
|
||||
self.draw_add_ui()
|
||||
|
||||
@@ -712,7 +712,8 @@ class CreateDrawing(bpy.types.Operator):
|
||||
}
|
||||
cached_linework -= edited_guids
|
||||
|
||||
files = {context.scene.BIMProperties.ifc_file: tool.Ifc.get()}
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
files = {bim_props.ifc_file: tool.Ifc.get()}
|
||||
|
||||
props = tool.Project.get_project_props()
|
||||
for link in props.links:
|
||||
@@ -730,7 +731,7 @@ class CreateDrawing(bpy.types.Operator):
|
||||
# Don't use draw.main() just whilst we're prototyping and experimenting
|
||||
# TODO: hash paths are never used
|
||||
ifc_hash = hashlib.md5(ifc_path.encode("utf-8")).hexdigest()
|
||||
ifc_cache_path = os.path.join(context.scene.BIMProperties.cache_dir, f"{ifc_hash}.h5")
|
||||
ifc_cache_path = os.path.join(bim_props.cache_dir, f"{ifc_hash}.h5")
|
||||
|
||||
self.serialiser.setFile(ifc)
|
||||
drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element, ifc_file=ifc)
|
||||
@@ -1618,7 +1619,8 @@ class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def poll(cls, context):
|
||||
props = tool.Drawing.get_document_props()
|
||||
# Won't be visible in UI anyway.
|
||||
if not props.sheets or not context.scene.BIMProperties.data_dir:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if not props.sheets or not bim_props.data_dir:
|
||||
return False
|
||||
if not tool.Drawing.get_active_drawing_item():
|
||||
cls.poll_message_set("No drawing selected.")
|
||||
@@ -1722,7 +1724,8 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not tool.Drawing.get_active_sheet_item(is_sheet=True):
|
||||
cls.poll_message_set("No sheet selected.")
|
||||
return False
|
||||
return props.sheets and context.scene.BIMProperties.data_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
return props.sheets and bim_props.data_dir
|
||||
|
||||
def invoke(self, context, event):
|
||||
# opening all sheets on shift+click
|
||||
@@ -2523,7 +2526,8 @@ class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not props.schedules:
|
||||
cls.poll_message_set("No schedule selected.")
|
||||
return False
|
||||
return props.schedules and props.sheets and context.scene.BIMProperties.data_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
return props.schedules and props.sheets and bim_props.data_dir
|
||||
|
||||
def _execute(self, context):
|
||||
props = tool.Drawing.get_document_props()
|
||||
@@ -2589,7 +2593,8 @@ class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not props.references:
|
||||
cls.poll_message_set("No reference selected.")
|
||||
return False
|
||||
return props.references and props.sheets and context.scene.BIMProperties.data_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
return props.references and props.sheets and bim_props.data_dir
|
||||
|
||||
def _execute(self, context):
|
||||
props = tool.Drawing.get_document_props()
|
||||
|
||||
@@ -76,34 +76,35 @@ class NewProject(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
bpy.ops.wm.read_homefile()
|
||||
pprops = tool.Project.get_project_props()
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
|
||||
if self.preset == "metric_m":
|
||||
pprops.export_schema = "IFC4"
|
||||
bpy.context.scene.unit_settings.system = "METRIC"
|
||||
bpy.context.scene.unit_settings.length_unit = "METERS"
|
||||
bpy.context.scene.BIMProperties.area_unit = "SQUARE_METRE"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "CUBIC_METRE"
|
||||
bim_props.area_unit = "SQUARE_METRE"
|
||||
bim_props.volume_unit = "CUBIC_METRE"
|
||||
pprops.template_file = "0"
|
||||
elif self.preset == "metric_mm":
|
||||
pprops.export_schema = "IFC4"
|
||||
bpy.context.scene.unit_settings.system = "METRIC"
|
||||
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
|
||||
bpy.context.scene.BIMProperties.area_unit = "SQUARE_METRE"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "CUBIC_METRE"
|
||||
bim_props.area_unit = "SQUARE_METRE"
|
||||
bim_props.volume_unit = "CUBIC_METRE"
|
||||
pprops.template_file = "0"
|
||||
elif self.preset == "imperial_ft":
|
||||
pprops.export_schema = "IFC4"
|
||||
bpy.context.scene.unit_settings.system = "IMPERIAL"
|
||||
bpy.context.scene.unit_settings.length_unit = "FEET"
|
||||
bpy.context.scene.BIMProperties.area_unit = "square foot"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "cubic foot"
|
||||
bim_props.area_unit = "square foot"
|
||||
bim_props.volume_unit = "cubic foot"
|
||||
pprops.template_file = "0"
|
||||
elif self.preset == "demo":
|
||||
pprops.export_schema = "IFC4"
|
||||
bpy.context.scene.unit_settings.system = "METRIC"
|
||||
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
|
||||
bpy.context.scene.BIMProperties.area_unit = "SQUARE_METRE"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "CUBIC_METRE"
|
||||
bim_props.area_unit = "SQUARE_METRE"
|
||||
bim_props.volume_unit = "CUBIC_METRE"
|
||||
pprops.template_file = "IFC4 Demo Template.ifc"
|
||||
|
||||
if self.preset != "wizard":
|
||||
@@ -979,7 +980,8 @@ class LoadProject(bpy.types.Operator, IFCFileSelector):
|
||||
if not self.is_advanced and not self.should_start_fresh_session:
|
||||
bpy.ops.bim.convert_to_blender()
|
||||
|
||||
context.scene.BIMProperties.ifc_file = filepath
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bim_props.ifc_file = filepath
|
||||
if not tool.Ifc.get():
|
||||
self.report(
|
||||
{"ERROR"},
|
||||
@@ -1039,13 +1041,15 @@ class RevertProject(bpy.types.Operator, IFCFileSelector):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.scene.BIMProperties.ifc_file:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if not props.ifc_file:
|
||||
cls.poll_message_set("IFC project need to be loaded and saved on the disk.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.bim.load_project(should_start_fresh_session=True, filepath=context.scene.BIMProperties.ifc_file)
|
||||
props = tool.Blender.get_bim_props()
|
||||
bpy.ops.bim.load_project(should_start_fresh_session=True, filepath=props.ifc_file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -1070,7 +1074,8 @@ class LoadProjectElements(bpy.types.Operator):
|
||||
filemode="a",
|
||||
level=logging.DEBUG,
|
||||
)
|
||||
settings = import_ifc.IfcImportSettings.factory(context, context.scene.BIMProperties.ifc_file, logger)
|
||||
props = tool.Blender.get_bim_props()
|
||||
settings = import_ifc.IfcImportSettings.factory(context, props.ifc_file, logger)
|
||||
settings.has_filter = self.props.filter_mode != "NONE"
|
||||
settings.should_filter_spatial_elements = self.props.should_filter_spatial_elements
|
||||
if self.props.filter_mode == "DECOMPOSITION":
|
||||
@@ -1560,7 +1565,8 @@ class ExportIFC(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
self.use_relative_path = tool.Project.get_project_props().use_relative_project_path
|
||||
if (filepath := context.scene.BIMProperties.ifc_file) and not self.should_save_as:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if (filepath := props.ifc_file) and not self.should_save_as:
|
||||
self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(filepath)))
|
||||
return self.execute(context)
|
||||
if not self.filepath:
|
||||
@@ -1621,7 +1627,6 @@ class ExportIFC(bpy.types.Operator):
|
||||
print("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
# New project created in Bonsai should be in recent projects too.
|
||||
tool.Project.add_recent_ifc_project(Path(output_file))
|
||||
scene = context.scene
|
||||
props = tool.Drawing.get_document_props()
|
||||
if not props.ifc_files:
|
||||
new = props.ifc_files.add()
|
||||
@@ -1629,12 +1634,13 @@ class ExportIFC(bpy.types.Operator):
|
||||
props = tool.Project.get_project_props()
|
||||
if props.use_relative_project_path and bpy.data.is_saved:
|
||||
output_file = os.path.relpath(output_file, bpy.path.abspath("//"))
|
||||
if scene.BIMProperties.ifc_file != output_file and extension not in ("ifczip", "ifcjson"):
|
||||
scene.BIMProperties.ifc_file = output_file
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if bim_props.ifc_file != output_file and extension not in ("ifczip", "ifcjson"):
|
||||
bim_props.ifc_file = output_file
|
||||
save_blend_file = bool(bpy.data.is_saved and bpy.data.is_dirty and bpy.data.filepath)
|
||||
if save_blend_file:
|
||||
bpy.ops.wm.save_mainfile(filepath=bpy.data.filepath)
|
||||
bpy.context.scene.BIMProperties.is_dirty = False
|
||||
bim_props.is_dirty = False
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
self.report(
|
||||
{"INFO"},
|
||||
|
||||
@@ -28,7 +28,7 @@ from bonsai.bim.module.project.data import ProjectData, LinksData
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.project.prop import LibraryElement, BIMProjectProperties
|
||||
from bonsai.bim.module.project.prop import LibraryElement, BIMProjectProperties, FilterCategory, Link
|
||||
|
||||
|
||||
def file_import_menu(self, context):
|
||||
@@ -151,7 +151,7 @@ class BIM_PT_project(Panel):
|
||||
|
||||
self.layout.use_property_decorate = False
|
||||
self.layout.use_property_split = True
|
||||
props = context.scene.BIMProperties
|
||||
props = tool.Blender.get_bim_props()
|
||||
pprops = self.props = tool.Project.get_project_props()
|
||||
self.file = tool.Ifc.get()
|
||||
if pprops.is_loading:
|
||||
@@ -305,7 +305,7 @@ class BIM_PT_project(Panel):
|
||||
|
||||
def draw_loaded_project_ui(self, context):
|
||||
# file name row
|
||||
props = context.scene.BIMProperties
|
||||
props = tool.Blender.get_bim_props()
|
||||
file_name_row = self.layout.row(align=True)
|
||||
file_name_row.label(text=os.path.basename(props.ifc_file), icon="FILE")
|
||||
self.draw_editing_buttons(context, file_name_row)
|
||||
@@ -315,7 +315,7 @@ class BIM_PT_project(Panel):
|
||||
|
||||
# file path row and actions section
|
||||
row = self.layout.row(align=True)
|
||||
if context.scene.BIMProperties.is_dirty:
|
||||
if props.is_dirty:
|
||||
row.label(text="Saved*", icon="EXPORT")
|
||||
else:
|
||||
row.label(text="Saved", icon="EXPORT")
|
||||
@@ -339,7 +339,7 @@ class BIM_PT_new_project_wizard(Panel):
|
||||
self.layout.use_property_decorate = False
|
||||
self.layout.use_property_split = True
|
||||
|
||||
props = context.scene.BIMProperties
|
||||
props = tool.Blender.get_bim_props()
|
||||
pprops = tool.Project.get_project_props()
|
||||
prop_with_search(self.layout, pprops, "export_schema")
|
||||
row = self.layout.row()
|
||||
@@ -542,7 +542,16 @@ class BIM_UL_library(UIList):
|
||||
|
||||
|
||||
class BIM_UL_filter_categories(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMProjectProperties,
|
||||
item: FilterCategory,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=f"{item.name} ({item.total_elements})")
|
||||
@@ -556,7 +565,17 @@ class BIM_UL_filter_categories(UIList):
|
||||
|
||||
|
||||
class BIM_UL_links(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMProjectProperties,
|
||||
item: Link,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
index,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
if item.is_loaded:
|
||||
|
||||
@@ -39,6 +39,7 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING, Literal, get_args
|
||||
|
||||
|
||||
class AddFilterGroup(Operator):
|
||||
@@ -144,13 +145,19 @@ class Search(Operator):
|
||||
bl_idname = "bim.search"
|
||||
bl_label = "Search"
|
||||
|
||||
property_group: bpy.props.StringProperty(name="Property Group", default="")
|
||||
PropertyGroupType = Literal["CsvProperties", "BIMSearchProperties"]
|
||||
property_group: bpy.props.EnumProperty(
|
||||
name="Property Group", items=[(i, i, "") for i in get_args(PropertyGroupType)]
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
property_group: PropertyGroupType
|
||||
|
||||
def execute(self, context):
|
||||
if self.property_group == "CsvProperties":
|
||||
props = context.scene.CsvProperties
|
||||
elif self.property_group == "BIMSearchProperties":
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
else:
|
||||
raise Exception(f"bim.search - unexpected property group name '{self.property_group}'.")
|
||||
|
||||
@@ -213,11 +220,12 @@ class LoadSearch(Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
filter_groups = tool.Search.get_filter_groups(self.module)
|
||||
group = tool.Ifc.get().by_id(int(context.scene.BIMSearchProperties.saved_searches))
|
||||
props = tool.Search.get_search_props()
|
||||
group = tool.Ifc.get().by_id(int(props.saved_searches))
|
||||
tool.Search.import_filter_query(tool.Search.get_group_query(group), filter_groups)
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
row = self.layout.row()
|
||||
row.prop(props, "saved_searches", text="")
|
||||
|
||||
@@ -239,7 +247,7 @@ class ColourByProperty(Operator):
|
||||
return result
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
query = props.colourscheme_query if props.colourscheme_key == "QUERY" else props.colourscheme_key
|
||||
|
||||
if not query:
|
||||
@@ -358,11 +366,11 @@ class SelectByProperty(Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
return props.active_colourscheme_index < len(props.colourscheme)
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
query = props.colourscheme_query if props.colourscheme_key == "QUERY" else props.colourscheme_key
|
||||
|
||||
if not query:
|
||||
@@ -420,7 +428,7 @@ class SaveColourscheme(Operator, tool.Ifc.Operator):
|
||||
if not self.name:
|
||||
return
|
||||
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
query = props.colourscheme_query
|
||||
|
||||
group = [g for g in tool.Ifc.get().by_type("IfcGroup") if g.Name == self.name]
|
||||
@@ -446,7 +454,7 @@ class LoadColourscheme(Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
group = tool.Ifc.get().by_id(int(props.saved_colourschemes))
|
||||
description = json.loads(group.Description)
|
||||
props.colourscheme_query = description.get("colourscheme_query")
|
||||
@@ -458,7 +466,7 @@ class LoadColourscheme(Operator, tool.Ifc.Operator):
|
||||
new.colour = data["colour"]
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
row = self.layout.row()
|
||||
row.prop(props, "saved_colourschemes", text="")
|
||||
|
||||
@@ -549,7 +557,7 @@ class ResetObjectColours(Operator):
|
||||
def execute(self, context):
|
||||
for obj in context.visible_objects:
|
||||
obj.color = (1, 1, 1, 1)
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
props.colourscheme.clear()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -562,7 +570,7 @@ class ToggleFilterSelection(Operator):
|
||||
action: EnumProperty(items=(("SELECT", "Select", ""), ("DESELECT", "Deselect", "")))
|
||||
|
||||
def execute(self, context):
|
||||
props = bpy.context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
self.selecting_actionbool = self.action == "SELECT"
|
||||
if props.filter_type == "CLASSES":
|
||||
for ifc_class in props.filter_classes:
|
||||
@@ -587,7 +595,7 @@ class ActivateIfcClassFilter(Operator):
|
||||
return True
|
||||
|
||||
def invoke(self, context, event):
|
||||
props = bpy.context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
props.filter_classes.clear()
|
||||
ifc_types = {}
|
||||
for obj in context.selected_objects:
|
||||
@@ -606,18 +614,20 @@ class ActivateIfcClassFilter(Operator):
|
||||
return context.window_manager.invoke_props_dialog(self, width=250)
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMSearchProperties.filter_classes.clear()
|
||||
props = tool.Search.get_search_props()
|
||||
props.filter_classes.clear()
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
props = tool.Search.get_search_props()
|
||||
self.layout.template_list(
|
||||
"BIM_UL_ifc_class_filter",
|
||||
"",
|
||||
context.scene.BIMSearchProperties,
|
||||
props,
|
||||
"filter_classes",
|
||||
context.scene.BIMSearchProperties,
|
||||
props,
|
||||
"filter_classes_index",
|
||||
rows=min(len(bpy.context.scene.BIMSearchProperties.filter_classes), 20),
|
||||
rows=min(len(props.filter_classes), 20),
|
||||
)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
|
||||
@@ -638,7 +648,7 @@ class ActivateContainerFilter(Operator):
|
||||
return True
|
||||
|
||||
def invoke(self, context, event):
|
||||
props = bpy.context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
props.filter_container.clear()
|
||||
|
||||
containers = {}
|
||||
@@ -661,18 +671,20 @@ class ActivateContainerFilter(Operator):
|
||||
return context.window_manager.invoke_props_dialog(self, width=250)
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMSearchProperties.filter_container.clear()
|
||||
props = tool.Search.get_search_props()
|
||||
props.filter_container.clear()
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
props = tool.Search.get_search_props()
|
||||
self.layout.template_list(
|
||||
"BIM_UL_ifc_building_storey_filter",
|
||||
"",
|
||||
context.scene.BIMSearchProperties,
|
||||
props,
|
||||
"filter_container",
|
||||
context.scene.BIMSearchProperties,
|
||||
props,
|
||||
"filter_container_index",
|
||||
rows=min(len(bpy.context.scene.BIMSearchProperties.filter_container), 20),
|
||||
rows=min(len(props.filter_container), 20),
|
||||
)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
|
||||
|
||||
@@ -33,33 +33,34 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
def get_element_key(self, context):
|
||||
def get_element_key(self: "BIMSearchProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not SelectSimilarData.is_loaded:
|
||||
SelectSimilarData.load()
|
||||
return SelectSimilarData.data["element_key"]
|
||||
|
||||
|
||||
def get_colourscheme_key(self, context):
|
||||
def get_colourscheme_key(self: "BIMSearchProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not ColourByPropertyData.is_loaded:
|
||||
ColourByPropertyData.load()
|
||||
return ColourByPropertyData.data["colourscheme_key"]
|
||||
|
||||
|
||||
def get_saved_searches(self, context):
|
||||
def get_saved_searches(self: "BIMSearchProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not SearchData.is_loaded:
|
||||
SearchData.load()
|
||||
return SearchData.data["saved_searches"]
|
||||
|
||||
|
||||
def get_saved_colourschemes(self, context):
|
||||
def get_saved_colourschemes(self: "BIMSearchProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not ColourByPropertyData.is_loaded:
|
||||
ColourByPropertyData.load()
|
||||
return ColourByPropertyData.data["saved_colourschemes"]
|
||||
|
||||
|
||||
def update_is_class_selected(self, context):
|
||||
def update_is_class_selected(self: "BIMFilterClasses", context: bpy.types.Context) -> None:
|
||||
if self.is_selected:
|
||||
for obj in self.unselected_objects:
|
||||
obj.obj.select_set(True)
|
||||
@@ -73,7 +74,7 @@ def update_is_class_selected(self, context):
|
||||
new.obj = obj
|
||||
|
||||
|
||||
def update_is_container_selected(self, context):
|
||||
def update_is_container_selected(self: "BIMFilterBuildingStoreys", context: bpy.types.Context) -> None:
|
||||
if self.is_selected:
|
||||
for obj in self.unselected_objects:
|
||||
obj.obj.select_set(True)
|
||||
@@ -87,15 +88,15 @@ def update_is_container_selected(self, context):
|
||||
new.obj = obj
|
||||
|
||||
|
||||
def update_show_flat_colours(self, context):
|
||||
def update_show_flat_colours(self: "BIMSearchProperties", context: bpy.types.Context) -> None:
|
||||
space = tool.Blender.get_view3d_space()
|
||||
assert space
|
||||
if self.show_flat_colours:
|
||||
space = tool.Blender.get_view3d_space()
|
||||
space.shading.light = "FLAT"
|
||||
space.shading.color_type = "OBJECT"
|
||||
space.shading.show_object_outline = True
|
||||
space.shading.show_cavity = True
|
||||
else:
|
||||
space = tool.Blender.get_view3d_space()
|
||||
space.shading.type = "SOLID"
|
||||
space.shading.light = "STUDIO"
|
||||
space.shading.show_object_outline = True
|
||||
@@ -108,6 +109,11 @@ class BIMFilterClasses(PropertyGroup):
|
||||
total: IntProperty(name="Total")
|
||||
unselected_objects: CollectionProperty(type=ObjProperty, name="Unfiltered Objects")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_selected: bool
|
||||
total: int
|
||||
unselected_objects: bpy.types.bpy_prop_collection_idprop[ObjProperty]
|
||||
|
||||
|
||||
class BIMFilterBuildingStoreys(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
@@ -115,12 +121,21 @@ class BIMFilterBuildingStoreys(PropertyGroup):
|
||||
total: IntProperty(name="Total")
|
||||
unselected_objects: CollectionProperty(type=ObjProperty, name="Unfiltered Objects")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_selected: bool
|
||||
total: int
|
||||
unselected_objects: bpy.types.bpy_prop_collection_idprop[ObjProperty]
|
||||
|
||||
|
||||
class BIMColour(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
total: IntProperty(name="Total")
|
||||
colour: FloatVectorProperty(name="Colour", subtype="COLOR", default=(1, 0, 0), min=0.0, max=1.0)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
total: int
|
||||
colour: tuple[float, float, float]
|
||||
|
||||
|
||||
class BIMSearchProperties(PropertyGroup):
|
||||
element_key: EnumProperty(items=get_element_key, name="Element Key")
|
||||
@@ -189,6 +204,29 @@ class BIMSearchProperties(PropertyGroup):
|
||||
filter_container_index: IntProperty(name="Filter Level Index")
|
||||
show_flat_colours: BoolProperty(name="Flat Colours", default=False, update=update_show_flat_colours)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
element_key: str
|
||||
filter_query: str
|
||||
filter_groups: bpy.types.bpy_prop_collection_idprop[BIMFilterGroup]
|
||||
facet: str
|
||||
saved_searches: str
|
||||
saved_colourschemes: str
|
||||
colourscheme_key: str
|
||||
colourscheme_query: str
|
||||
palette: str
|
||||
min_mode: Literal["AUTO", "MANUAL"]
|
||||
max_mode: Literal["AUTO", "MANUAL"]
|
||||
min_value: float
|
||||
max_value: float
|
||||
colourscheme: bpy.types.bpy_prop_collection_idprop[BIMColour]
|
||||
active_colourscheme_index: int
|
||||
filter_type: str
|
||||
filter_classes: bpy.types.bpy_prop_collection_idprop[BIMFilterClasses]
|
||||
filter_classes_index: int
|
||||
filter_container: bpy.types.bpy_prop_collection_idprop[BIMFilterBuildingStoreys]
|
||||
filter_container_index: int
|
||||
show_flat_colours: bool
|
||||
|
||||
|
||||
def get_classes(self, ifc_product):
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import bonsai.tool as tool
|
||||
import bonsai.bim.helper
|
||||
from bpy.types import Panel
|
||||
from bonsai.bim.module.search.data import SearchData, ColourByPropertyData, SelectSimilarData
|
||||
@@ -34,7 +35,7 @@ class BIM_PT_search(Panel):
|
||||
if not SearchData.is_loaded:
|
||||
SearchData.load()
|
||||
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
|
||||
bonsai.bim.helper.draw_filter(self.layout, props.filter_groups, SearchData, "search")
|
||||
|
||||
@@ -73,7 +74,7 @@ class BIM_PT_colour_by_property(Panel):
|
||||
if not ColourByPropertyData.is_loaded:
|
||||
ColourByPropertyData.load()
|
||||
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"{len(ColourByPropertyData.data['saved_colourschemes'])} Saved Colourschemes")
|
||||
@@ -127,7 +128,7 @@ class BIM_PT_select_similar(Panel):
|
||||
if not SelectSimilarData.is_loaded:
|
||||
SelectSimilarData.load()
|
||||
|
||||
props = context.scene.BIMSearchProperties
|
||||
props = tool.Search.get_search_props()
|
||||
|
||||
if SelectSimilarData.data["element_key"]:
|
||||
row = self.layout.row(align=True)
|
||||
|
||||
@@ -30,21 +30,22 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
def get_unit_classes(self, context):
|
||||
def get_unit_classes(self: "BIMUnitProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not UnitsData.is_loaded:
|
||||
UnitsData.load()
|
||||
return UnitsData.data["unit_classes"]
|
||||
|
||||
|
||||
def get_conversion_unit_types(self, context):
|
||||
def get_conversion_unit_types(self: "BIMUnitProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not UnitsData.is_loaded:
|
||||
UnitsData.load()
|
||||
return UnitsData.data["conversion_unit_types"]
|
||||
|
||||
|
||||
def get_named_unit_types(self, context):
|
||||
def get_named_unit_types(self: "BIMUnitProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not UnitsData.is_loaded:
|
||||
UnitsData.load()
|
||||
return UnitsData.data["named_unit_types"]
|
||||
@@ -57,6 +58,12 @@ class Unit(PropertyGroup):
|
||||
ifc_class: StringProperty(name="IFC Class")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
unit_type: str
|
||||
is_assigned: bool
|
||||
ifc_class: str
|
||||
ifc_definition_id: int
|
||||
|
||||
|
||||
class BIMUnitProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
@@ -67,3 +74,13 @@ class BIMUnitProperties(PropertyGroup):
|
||||
conversion_unit_types: EnumProperty(items=get_conversion_unit_types, name="Conversion Unit Types")
|
||||
named_unit_types: EnumProperty(items=get_named_unit_types, name="Named Unit Types")
|
||||
unit_attributes: CollectionProperty(name="Unit Attributes", type=Attribute)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
units: bpy.types.bpy_prop_collection_idprop[Unit]
|
||||
active_unit_index: int
|
||||
active_unit_id: int
|
||||
unit_classes: str
|
||||
conversion_unit_types: str
|
||||
named_unit_types: str
|
||||
unit_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
|
||||
|
||||
@@ -41,7 +41,7 @@ class BIM_PT_units(Panel):
|
||||
if not UnitsData.is_loaded:
|
||||
UnitsData.load()
|
||||
|
||||
self.props = context.scene.BIMUnitProperties
|
||||
self.props = tool.Unit.get_unit_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Units Found".format(UnitsData.data["total_units"]), icon="SNAP_GRID")
|
||||
@@ -103,7 +103,7 @@ class BIM_PT_units(Panel):
|
||||
|
||||
class BIM_UL_units(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
props = context.scene.BIMUnitProperties
|
||||
props = tool.Unit.get_unit_props()
|
||||
if item:
|
||||
icon = "MOD_MESHDEFORM"
|
||||
if item.ifc_class == "IfcSIUnit":
|
||||
|
||||
@@ -39,9 +39,11 @@ class WebData:
|
||||
|
||||
@classmethod
|
||||
def get_ifc_file_name(cls):
|
||||
filename = os.path.basename(bpy.context.scene.BIMProperties.ifc_file)
|
||||
props = tool.Blender.get_bim_props()
|
||||
filename = os.path.basename(props.ifc_file)
|
||||
return filename
|
||||
|
||||
@classmethod
|
||||
def get_is_dirty(cls):
|
||||
return bpy.context.scene.BIMProperties.is_dirty
|
||||
props = tool.Blender.get_bim_props()
|
||||
return props.is_dirty
|
||||
|
||||
@@ -130,7 +130,8 @@ class CloseBlendWarning(bpy.types.Operator):
|
||||
bl_label = "Close Blend Warning"
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMProperties.has_blend_warning = False
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.has_blend_warning = False
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
@@ -213,11 +214,13 @@ class SelectIfcFile(bpy.types.Operator, IFCFileSelector):
|
||||
|
||||
def execute(self, context):
|
||||
if self.is_existing_ifc_file():
|
||||
context.scene.BIMProperties.ifc_file = self.get_filepath()
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.ifc_file = self.get_filepath()
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
filepath = Path(context.scene.BIMProperties.ifc_file)
|
||||
props = tool.Blender.get_bim_props()
|
||||
filepath = Path(props.ifc_file)
|
||||
res = tool.Blender.operator_invoke_filepath_hotkeys(self, context, event, filepath)
|
||||
if res is not None:
|
||||
return res
|
||||
@@ -575,7 +578,8 @@ class BIM_OT_add_section_plane(bpy.types.Operator):
|
||||
backfacing.location = mix_backfacing.location + Vector((-200, 200))
|
||||
|
||||
emission = nodes.new(type="ShaderNodeEmission")
|
||||
emission.inputs[0].default_value = list(context.scene.BIMProperties.section_plane_colour) + [1]
|
||||
props = tool.Blender.get_bim_props()
|
||||
emission.inputs[0].default_value = list(props.section_plane_colour) + [1]
|
||||
emission.location = mix_backfacing.location - Vector((200, 150))
|
||||
|
||||
cut_obj = nodes.new(type="ShaderNodeTexCoord")
|
||||
@@ -639,7 +643,8 @@ class BIM_OT_add_section_plane(bpy.types.Operator):
|
||||
material = bpy.data.materials.new("Section Override")
|
||||
material.use_nodes = True
|
||||
|
||||
if context.scene.BIMProperties.should_section_selected_objects:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if props.should_section_selected_objects:
|
||||
objects = list(context.selected_objects)
|
||||
else:
|
||||
objects = list(context.visible_objects)
|
||||
@@ -814,7 +819,8 @@ class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
settings.logger.info("Import finished in {:.2f} seconds".format(time.time() - start))
|
||||
print("Import finished in {:.2f} seconds".format(time.time() - start))
|
||||
|
||||
context.scene.BIMProperties.ifc_file = self.filepath
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bim_props.ifc_file = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -852,7 +858,8 @@ class FetchObjectPassport(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
# TODO: this is dead code, awaiting reimplementation. See #1222.
|
||||
for reference in context.active_object.BIMObjectProperties.document_references:
|
||||
reference = context.scene.BIMProperties.document_references[reference.name]
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
reference = bim_props.document_references[reference.name]
|
||||
if reference.location[-6:] == ".blend":
|
||||
self.fetch_blender(reference, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -119,23 +119,27 @@ def get_attribute_enum_values(prop: "Attribute", context: bpy.types.Context) ->
|
||||
def update_schema_dir(self: "BIMProperties", context: bpy.types.Context) -> None:
|
||||
import bonsai.bim.schema
|
||||
|
||||
bonsai.bim.schema.ifc.schema_dir = context.scene.BIMProperties.schema_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bonsai.bim.schema.ifc.schema_dir = bim_props.schema_dir
|
||||
|
||||
|
||||
def update_data_dir(self: "BIMProperties", context: bpy.types.Context) -> None:
|
||||
import bonsai.bim.schema
|
||||
|
||||
bonsai.bim.schema.ifc.data_dir = context.scene.BIMProperties.data_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bonsai.bim.schema.ifc.data_dir = bim_props.data_dir
|
||||
|
||||
|
||||
def update_cache_dir(self: "BIMProperties", context: bpy.types.Context) -> None:
|
||||
import bonsai.bim.schema
|
||||
|
||||
bonsai.bim.schema.ifc.cache_dir = context.scene.BIMProperties.cache_dir
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
bonsai.bim.schema.ifc.cache_dir = bim_props.cache_dir
|
||||
|
||||
|
||||
def update_ifc_file(self: "BIMProperties", context: bpy.types.Context) -> None:
|
||||
if context.scene.BIMProperties.ifc_file:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if bim_props.ifc_file:
|
||||
bonsai.bim.handler.loadIfcStore(context.scene)
|
||||
|
||||
|
||||
@@ -331,10 +335,31 @@ class Attribute(PropertyGroup):
|
||||
|
||||
if TYPE_CHECKING:
|
||||
name: str
|
||||
display_name: str
|
||||
description: str
|
||||
ifc_class: str
|
||||
data_type: AttributeDataType
|
||||
special_type: AttributeSpecialType
|
||||
string_value: str
|
||||
bool_value: bool
|
||||
int_value: int
|
||||
float_value: float
|
||||
length_value: float
|
||||
enum_items: str
|
||||
enum_descriptions: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
enum_value: str
|
||||
filepath_value: MultipleFileSelect
|
||||
filter_glob: str
|
||||
is_null: bool
|
||||
is_optional: bool
|
||||
is_uri: bool
|
||||
is_selected: bool
|
||||
value_min: float
|
||||
value_min_constraint: bool
|
||||
value_max: float
|
||||
value_max_constraint: bool
|
||||
metadata: str
|
||||
update: str
|
||||
|
||||
def get_value(self) -> Union[str, float, int, bool, None]:
|
||||
if self.is_optional and self.is_null:
|
||||
@@ -439,6 +464,13 @@ class BIMAreaProperties(PropertyGroup):
|
||||
active_tab: BoolProperty(default=True, name="Active Tab")
|
||||
inactive_tab: BoolProperty(default=False, name="Inactive Tab")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
tab: str
|
||||
previous_tab: str
|
||||
alt_tab: str
|
||||
active_tab: bool
|
||||
inactive_tab: bool
|
||||
|
||||
|
||||
# BIMAreaProperties exists per area and is setup on load post. However, for new
|
||||
# or temporary screens, they may not be setup yet, so this global tab
|
||||
@@ -449,6 +481,11 @@ class BIMTabProperties(PropertyGroup):
|
||||
active_tab: BoolProperty(default=True, name="Active Tab")
|
||||
inactive_tab: BoolProperty(default=False, name="Inactive Tab")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
tab: str
|
||||
active_tab: bool
|
||||
inactive_tab: bool
|
||||
|
||||
|
||||
class BIMProperties(PropertyGroup):
|
||||
is_dirty: BoolProperty(name="Is Dirty", default=False)
|
||||
@@ -517,6 +554,21 @@ class BIMProperties(PropertyGroup):
|
||||
name="IFC Volume Unit",
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_dirty: bool
|
||||
schema_dir: str
|
||||
data_dir: str
|
||||
cache_dir: str
|
||||
has_blend_warning: bool
|
||||
pset_dir: str
|
||||
ifc_file: str
|
||||
last_transaction: str
|
||||
should_section_selected_objects: bool
|
||||
section_plane_colour: tuple[float, float, float]
|
||||
section_line_decorator_width: float
|
||||
area_unit: str
|
||||
volume_unit: str
|
||||
|
||||
|
||||
class IfcParameter(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
@@ -547,6 +599,7 @@ class PsetQto(PropertyGroup):
|
||||
|
||||
class GlobalId(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
|
||||
class BIMCollectionProperties(PropertyGroup):
|
||||
@@ -556,11 +609,14 @@ class BIMCollectionProperties(PropertyGroup):
|
||||
obj: Union[bpy.types.Object, None]
|
||||
|
||||
|
||||
BlenderOffsetType = Literal["NONE", "OBJECT_PLACEMENT", "CARTESIAN_POINT", "NOT_APPLICABLE"]
|
||||
|
||||
|
||||
class BIMObjectProperties(PropertyGroup):
|
||||
collection: PointerProperty(type=bpy.types.Collection)
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
blender_offset_type: EnumProperty(
|
||||
items=[(o, o, "") for o in ["NONE", "OBJECT_PLACEMENT", "CARTESIAN_POINT", "NOT_APPLICABLE"]],
|
||||
items=[(o, o, "") for o in get_args(BlenderOffsetType)],
|
||||
name="Blender Offset",
|
||||
default="NONE",
|
||||
)
|
||||
@@ -570,6 +626,16 @@ class BIMObjectProperties(PropertyGroup):
|
||||
location_checksum: StringProperty(name="Location Checksum")
|
||||
rotation_checksum: StringProperty(name="Rotation Checksum")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
collection: Union[bpy.types.Collection, None]
|
||||
ifc_definition_id: int
|
||||
blender_offset_type: BlenderOffsetType
|
||||
cartesian_point_offset: str
|
||||
is_reassigning_class: bool
|
||||
is_renaming: bool
|
||||
location_checksum: str
|
||||
rotation_checksum: str
|
||||
|
||||
|
||||
def get_profiles(self: "BIMMeshProperties", context: bpy.types.Context):
|
||||
from bonsai.bim.module.model.data import ItemData
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.pset
|
||||
import bonsai.tool as tool
|
||||
import bpy
|
||||
import bpy_restrict_state
|
||||
|
||||
|
||||
class IfcSchema:
|
||||
@@ -47,10 +49,16 @@ class IfcSchema:
|
||||
self.psetqto.get_applicable.cache_clear()
|
||||
self.psetqto.get_applicable_names.cache_clear()
|
||||
self.psetqto.get_by_name.cache_clear()
|
||||
|
||||
# During register we cannot access the context either way.
|
||||
if isinstance(bpy.context, bpy_restrict_state._RestrictContext):
|
||||
return
|
||||
for path in tool.Blender.get_data_dir_paths("pset", "*.ifc"):
|
||||
self.psetqto.templates.append(ifcopenshell.open(path))
|
||||
|
||||
|
||||
# TODO: do we really need to load it on module import?
|
||||
# Loading it on IFC load should be enough.
|
||||
ifc = IfcSchema()
|
||||
|
||||
|
||||
|
||||
+12
-10
@@ -121,7 +121,7 @@ class BIM_PT_section_plane(Panel):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
props = context.scene.BIMProperties
|
||||
props = tool.Blender.get_bim_props()
|
||||
|
||||
layout.prop(props, "should_section_selected_objects")
|
||||
layout.prop(props, "section_plane_colour")
|
||||
@@ -381,12 +381,13 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
layout.prop(props, "occurrence_name_function")
|
||||
|
||||
def draw_directories(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None:
|
||||
props = tool.Blender.get_bim_props()
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.BIMProperties, "data_dir")
|
||||
row.prop(props, "data_dir")
|
||||
row.operator("bim.select_dir", icon="FILE_FOLDER", text="").data_path = "scene.BIMProperties.data_dir"
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.BIMProperties, "cache_dir")
|
||||
row.prop(props, "cache_dir")
|
||||
row.operator("bim.select_dir", icon="FILE_FOLDER", text="").data_path = "scene.BIMProperties.cache_dir"
|
||||
|
||||
row = layout.row(align=True)
|
||||
@@ -394,7 +395,8 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
row.operator("bim.select_dir", icon="FILE_FOLDER", text="").data_path = "preferences.tmp_dir"
|
||||
|
||||
def draw_drawing_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None:
|
||||
layout.prop(context.scene.BIMProperties, "pset_dir")
|
||||
props = tool.Blender.get_bim_props()
|
||||
layout.prop(props, "pset_dir")
|
||||
dprops = tool.Drawing.get_document_props()
|
||||
layout.prop(dprops, "sheets_dir")
|
||||
layout.prop(dprops, "layouts_dir")
|
||||
@@ -510,8 +512,8 @@ class BIM_PT_tabs(Panel):
|
||||
if not tool.Ifc.get():
|
||||
return
|
||||
|
||||
props = context.scene.BIMProperties
|
||||
if props.has_blend_warning:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if bim_props.has_blend_warning:
|
||||
box = self.layout.box()
|
||||
box.alert = True
|
||||
row = box.row(align=True)
|
||||
@@ -557,11 +559,11 @@ class BIM_PT_tab_new_project_wizard(Panel):
|
||||
def poll(cls, context):
|
||||
if not tool.Blender.is_tab(context, "PROJECT"):
|
||||
return False
|
||||
props = context.scene.BIMProperties
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
pprops = tool.Project.get_project_props()
|
||||
if pprops.is_loading:
|
||||
return False
|
||||
elif tool.Ifc.get() or props.ifc_file:
|
||||
elif tool.Ifc.get() or bim_props.ifc_file:
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -579,11 +581,11 @@ class BIM_PT_tab_project_info(Panel):
|
||||
def poll(cls, context):
|
||||
if not tool.Blender.is_tab(context, "PROJECT"):
|
||||
return False
|
||||
props = context.scene.BIMProperties
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
pprops = tool.Project.get_project_props()
|
||||
if pprops.is_loading:
|
||||
return True
|
||||
elif tool.Ifc.get() or props.ifc_file:
|
||||
elif tool.Ifc.get() or bim_props.ifc_file:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -37,9 +37,12 @@ from mathutils import Vector
|
||||
from pathlib import Path
|
||||
from functools import lru_cache
|
||||
from bonsai.bim.ifc import IFC_CONNECTED_TYPE
|
||||
from typing import Any, Optional, Union, Literal, Iterable, Callable, TypeVar, Generator
|
||||
from typing import Any, Optional, Union, Literal, Iterable, Callable, TypeVar, Generator, TYPE_CHECKING
|
||||
from typing_extensions import assert_never
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.prop import BIMProperties
|
||||
|
||||
|
||||
VIEWPORT_ATTRIBUTES = [
|
||||
"view_matrix",
|
||||
@@ -1477,10 +1480,8 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def get_user_data_dir(cls) -> Path:
|
||||
try:
|
||||
return Path(bpy.context.scene.BIMProperties.data_dir)
|
||||
except AttributeError:
|
||||
return Path()
|
||||
props = tool.Blender.get_bim_props()
|
||||
return Path(props.data_dir)
|
||||
|
||||
@classmethod
|
||||
def get_data_dir_path(cls, relative_path: Union[str, Path]) -> Path:
|
||||
@@ -1538,3 +1539,9 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
dct = {cls.bl_idname: cls.ifc_element_type for cls in (BimTool.__subclasses__())}
|
||||
return types.MappingProxyType(dct)
|
||||
|
||||
@classmethod
|
||||
def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties:
|
||||
if scene is None:
|
||||
scene = bpy.context.scene
|
||||
return scene.BIMProperties
|
||||
|
||||
@@ -86,10 +86,11 @@ class Brick(bonsai.core.tool.Brick):
|
||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
||||
ns = Namespace(namespace)
|
||||
brick_project = ns[project.GlobalId]
|
||||
props = tool.Blender.get_bim_props()
|
||||
with BrickStore.new_changeset() as cs:
|
||||
cs.add((brick_project, A, REF.ifcProject))
|
||||
cs.add((brick_project, REF.ifcProjectID, Literal(project.GlobalId)))
|
||||
cs.add((brick_project, REF.ifcFileLocation, Literal(bpy.context.scene.BIMProperties.ifc_file)))
|
||||
cs.add((brick_project, REF.ifcFileLocation, Literal(props.ifc_file)))
|
||||
if project.Name:
|
||||
cs.add((brick_project, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal(project.Name)))
|
||||
return str(brick_project)
|
||||
|
||||
@@ -54,7 +54,8 @@ class Debug(bonsai.core.tool.Debug):
|
||||
|
||||
@classmethod
|
||||
def purge_hdf5_cache(cls) -> None:
|
||||
cache_dir = bpy.context.scene.BIMProperties.cache_dir
|
||||
props = tool.Blender.get_bim_props()
|
||||
cache_dir = props.cache_dir
|
||||
filelist = [f for f in os.listdir(cache_dir) if f.endswith(".h5")]
|
||||
for f in filelist:
|
||||
try:
|
||||
|
||||
@@ -16,56 +16,68 @@
|
||||
# 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.util.system
|
||||
import bonsai.bim.helper
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from typing import Any, Union, Sequence
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.document.prop import BIMDocumentProperties
|
||||
|
||||
|
||||
class Document(bonsai.core.tool.Document):
|
||||
@classmethod
|
||||
def get_document_props(cls) -> BIMDocumentProperties:
|
||||
return bpy.context.scene.BIMDocumentProperties
|
||||
|
||||
@classmethod
|
||||
def add_breadcrumb(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
new = props.breadcrumbs.add()
|
||||
new.name = str(document.id())
|
||||
|
||||
@classmethod
|
||||
def clear_breadcrumbs(cls) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
props.breadcrumbs.clear()
|
||||
|
||||
@classmethod
|
||||
def clear_document_tree(cls) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
props.documents.clear()
|
||||
|
||||
@classmethod
|
||||
def disable_editing_document(cls) -> None:
|
||||
bpy.context.scene.BIMDocumentProperties.active_document_id = 0
|
||||
props = cls.get_document_props()
|
||||
props.active_document_id = 0
|
||||
|
||||
@classmethod
|
||||
def disable_editing_ui(cls) -> None:
|
||||
bpy.context.scene.BIMDocumentProperties.is_editing = False
|
||||
props = cls.get_document_props()
|
||||
props.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def enable_editing_ui(cls) -> None:
|
||||
bpy.context.scene.BIMDocumentProperties.is_editing = True
|
||||
props = cls.get_document_props()
|
||||
props.is_editing = True
|
||||
|
||||
@classmethod
|
||||
def export_document_attributes(cls) -> dict[str, Any]:
|
||||
return bonsai.bim.helper.export_attributes(bpy.context.scene.BIMDocumentProperties.document_attributes)
|
||||
props = cls.get_document_props()
|
||||
return bonsai.bim.helper.export_attributes(props.document_attributes)
|
||||
|
||||
@classmethod
|
||||
def get_active_breadcrumb(cls) -> Union[ifcopenshell.entity_instance, None]:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
if len(props.breadcrumbs):
|
||||
return tool.Ifc.get().by_id(int(props.breadcrumbs[-1].name))
|
||||
|
||||
@classmethod
|
||||
def import_document_attributes(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
props.document_attributes.clear()
|
||||
|
||||
def callback(attr_name: str, _, data: dict[str, Any]) -> Union[bool, None]:
|
||||
@@ -86,7 +98,7 @@ class Document(bonsai.core.tool.Document):
|
||||
|
||||
@classmethod
|
||||
def import_project_documents(cls) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
props.documents.clear()
|
||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
||||
for rel in project.HasAssociations or []:
|
||||
@@ -100,7 +112,7 @@ class Document(bonsai.core.tool.Document):
|
||||
|
||||
@classmethod
|
||||
def import_references(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
is_ifc2x3 = tool.Ifc.get_schema() == "IFC2X3"
|
||||
references = cls.get_document_references(document)
|
||||
for element in references:
|
||||
@@ -115,7 +127,7 @@ class Document(bonsai.core.tool.Document):
|
||||
|
||||
@classmethod
|
||||
def import_subdocuments(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
if document.IsPointer:
|
||||
for element in document.IsPointer[0].RelatedDocuments or []:
|
||||
new = props.documents.add()
|
||||
@@ -130,13 +142,14 @@ class Document(bonsai.core.tool.Document):
|
||||
|
||||
@classmethod
|
||||
def remove_latest_breadcrumb(cls) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = cls.get_document_props()
|
||||
if len(props.breadcrumbs):
|
||||
props.breadcrumbs.remove(len(props.breadcrumbs) - 1)
|
||||
|
||||
@classmethod
|
||||
def set_active_document(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
bpy.context.scene.BIMDocumentProperties.active_document_id = document.id()
|
||||
props = cls.get_document_props()
|
||||
props.active_document_id = document.id()
|
||||
|
||||
@classmethod
|
||||
def get_document_information_id(cls, document: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
|
||||
@@ -340,8 +340,8 @@ class IfcGit:
|
||||
|
||||
@classmethod
|
||||
def get_revisions_step_ids(cls) -> Union[STEP_IDS, None]:
|
||||
|
||||
path_ifc = bpy.data.scenes["Scene"].BIMProperties.ifc_file
|
||||
props = tool.Blender.get_bim_props()
|
||||
path_ifc = tool.Blender.get_bim_props().ifc_file
|
||||
props = bpy.context.scene.IfcGitProperties
|
||||
repo = IfcGitRepo.repo
|
||||
item = props.ifcgit_commits[props.commit_index]
|
||||
|
||||
@@ -456,7 +456,8 @@ class Polyline(bonsai.core.tool.Polyline):
|
||||
dprops = tool.Drawing.get_document_props()
|
||||
precision = dprops.imperial_precision
|
||||
if is_area:
|
||||
area_unit = bpy.context.scene.BIMProperties.area_unit
|
||||
props = tool.Blender.get_bim_props()
|
||||
area_unit = props.area_unit
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(), unit_type=area_unit)
|
||||
else:
|
||||
precision = None
|
||||
|
||||
@@ -70,7 +70,8 @@ class Project(bonsai.core.tool.Project):
|
||||
|
||||
@classmethod
|
||||
def load_pset_templates(cls):
|
||||
pset_dir = tool.Ifc.resolve_uri(bpy.context.scene.BIMProperties.pset_dir)
|
||||
props = tool.Blender.get_bim_props()
|
||||
pset_dir = tool.Ifc.resolve_uri(props.pset_dir)
|
||||
if os.path.isdir(pset_dir):
|
||||
for path in Path(pset_dir).glob("*.ifc"):
|
||||
bonsai.bim.schema.ifc.psetqto.templates.append(ifcopenshell.open(path))
|
||||
|
||||
@@ -133,7 +133,8 @@ class PsetTemplate(bonsai.core.tool.PsetTemplate):
|
||||
for f in tool.Blender.get_data_dir_paths("pset", "*.ifc"):
|
||||
paths.append((f, "Global Pset Template"))
|
||||
|
||||
pset_dir = Path(tool.Ifc.resolve_uri(bpy.context.scene.BIMProperties.pset_dir))
|
||||
props = tool.Blender.get_bim_props()
|
||||
pset_dir = Path(tool.Ifc.resolve_uri(props.pset_dir))
|
||||
if pset_dir.is_dir():
|
||||
for path in Path(pset_dir).glob("*.ifc"):
|
||||
paths.append((path, "Project Pset Template"))
|
||||
|
||||
@@ -30,9 +30,14 @@ from typing import Union, Literal, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.prop import BIMFilterGroup
|
||||
from bonsai.bim.module.search.prop import BIMSearchProperties
|
||||
|
||||
|
||||
class Search(bonsai.core.tool.Search):
|
||||
@classmethod
|
||||
def get_search_props(cls) -> BIMSearchProperties:
|
||||
return bpy.context.scene.BIMSearchProperties
|
||||
|
||||
@classmethod
|
||||
def get_group_query(cls, group: ifcopenshell.entity_instance) -> str:
|
||||
return json.loads(group.Description)["query"]
|
||||
@@ -40,7 +45,7 @@ class Search(bonsai.core.tool.Search):
|
||||
@classmethod
|
||||
def get_filter_groups(cls, module: str) -> bpy.types.bpy_prop_collection_idprop[BIMFilterGroup]:
|
||||
if module == "search":
|
||||
return bpy.context.scene.BIMSearchProperties.filter_groups
|
||||
return cls.get_search_props().filter_groups
|
||||
elif module == "csv":
|
||||
return bpy.context.scene.CsvProperties.filter_groups
|
||||
elif module == "diff":
|
||||
|
||||
@@ -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 json
|
||||
import math
|
||||
@@ -23,24 +24,34 @@ import ifcopenshell
|
||||
import bonsai.bim.helper
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from typing import Union, Literal, Any
|
||||
from typing import Union, Literal, Any, TYPE_CHECKING
|
||||
from typing_extensions import assert_never
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.unit.prop import BIMUnitProperties
|
||||
|
||||
|
||||
class Unit(bonsai.core.tool.Unit):
|
||||
UNIT_TYPE = Literal["LENGTHUNIT", "AREAUNIT", "VOLUMEUNIT"]
|
||||
|
||||
@classmethod
|
||||
def get_unit_props(cls) -> BIMUnitProperties:
|
||||
return bpy.context.scene.BIMUnitProperties
|
||||
|
||||
@classmethod
|
||||
def clear_active_unit(cls) -> None:
|
||||
bpy.context.scene.BIMUnitProperties.active_unit_id = 0
|
||||
props = cls.get_unit_props()
|
||||
props.active_unit_id = 0
|
||||
|
||||
@classmethod
|
||||
def disable_editing_units(cls) -> None:
|
||||
bpy.context.scene.BIMUnitProperties.is_editing = False
|
||||
props = cls.get_unit_props()
|
||||
props.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def enable_editing_units(cls) -> None:
|
||||
bpy.context.scene.BIMUnitProperties.is_editing = True
|
||||
props = cls.get_unit_props()
|
||||
props.is_editing = True
|
||||
|
||||
@classmethod
|
||||
def export_unit_attributes(cls) -> dict[str, Any]:
|
||||
@@ -52,11 +63,12 @@ class Unit(bonsai.core.tool.Unit):
|
||||
attributes[prop.name] = (0, 0, 0, 0, 0, 0, 0)
|
||||
return True
|
||||
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
props = cls.get_unit_props()
|
||||
return bonsai.bim.helper.export_attributes(props.unit_attributes, callback=callback)
|
||||
|
||||
@classmethod
|
||||
def get_scene_unit_name(cls, unit_type: UNIT_TYPE) -> str:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if unit_type == "LENGTHUNIT":
|
||||
props = bpy.context.scene.unit_settings
|
||||
if props.length_unit == "MILES":
|
||||
@@ -69,23 +81,24 @@ class Unit(bonsai.core.tool.Unit):
|
||||
return "thou"
|
||||
return "foot"
|
||||
elif unit_type == "AREAUNIT":
|
||||
return bpy.context.scene.BIMProperties.area_unit
|
||||
return bim_props.area_unit
|
||||
elif unit_type == "VOLUMEUNIT":
|
||||
return bpy.context.scene.BIMProperties.volume_unit
|
||||
return bim_props.volume_unit
|
||||
else:
|
||||
assert_never()
|
||||
|
||||
@classmethod
|
||||
def get_scene_unit_si_prefix(cls, unit_type: UNIT_TYPE) -> Union[str, None]:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
if unit_type == "LENGTHUNIT":
|
||||
props = bpy.context.scene.unit_settings
|
||||
if props.length_unit == "ADAPTIVE" or props.length_unit == "METERS":
|
||||
return
|
||||
return props.length_unit.replace("METERS", "")
|
||||
elif unit_type == "AREAUNIT":
|
||||
unit = bpy.context.scene.BIMProperties.area_unit
|
||||
unit = bim_props.area_unit
|
||||
elif unit_type == "VOLUMEUNIT":
|
||||
unit = bpy.context.scene.BIMProperties.volume_unit
|
||||
unit = bim_props.volume_unit
|
||||
else:
|
||||
assert_never(unit_type)
|
||||
if "/" in unit:
|
||||
@@ -93,9 +106,11 @@ class Unit(bonsai.core.tool.Unit):
|
||||
|
||||
@classmethod
|
||||
def import_unit_attributes(cls, unit: ifcopenshell.entity_instance) -> None:
|
||||
props = cls.get_unit_props()
|
||||
|
||||
def callback(name, prop, data):
|
||||
if name == "Dimensions" and data["type"] != "IfcSIUnit":
|
||||
new = bpy.context.scene.BIMUnitProperties.unit_attributes.add()
|
||||
new = props.unit_attributes.add()
|
||||
new.name = name
|
||||
new.is_null = data[name] is None
|
||||
new.is_optional = False
|
||||
@@ -103,13 +118,12 @@ class Unit(bonsai.core.tool.Unit):
|
||||
new.string_value = json.dumps([e for e in tool.Ifc.get().by_id(data["id"]).Dimensions])
|
||||
return True
|
||||
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
props.unit_attributes.clear()
|
||||
bonsai.bim.helper.import_attributes2(unit, props.unit_attributes, callback=callback)
|
||||
|
||||
@classmethod
|
||||
def import_units(cls) -> None:
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
props = tool.Unit.get_unit_props()
|
||||
props.units.clear()
|
||||
|
||||
units = []
|
||||
@@ -158,7 +172,8 @@ class Unit(bonsai.core.tool.Unit):
|
||||
|
||||
@classmethod
|
||||
def set_active_unit(cls, unit: ifcopenshell.entity_instance) -> None:
|
||||
bpy.context.scene.BIMUnitProperties.active_unit_id = unit.id()
|
||||
props = cls.get_unit_props()
|
||||
props.active_unit_id = unit.id()
|
||||
|
||||
@classmethod
|
||||
def get_project_currency_unit(cls) -> Union[ifcopenshell.entity_instance, None]:
|
||||
|
||||
@@ -730,7 +730,8 @@ class Web(bonsai.core.tool.Web):
|
||||
if operator_data["type"] == "getDrawings":
|
||||
drawings_data = []
|
||||
sheets_data = []
|
||||
ifc_file_dir = os.path.dirname(bpy.context.scene.BIMProperties.ifc_file)
|
||||
props = tool.Blender.get_bim_props()
|
||||
ifc_file_dir = os.path.dirname(props.ifc_file)
|
||||
|
||||
sheets = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SHEET"]
|
||||
for sheet in sorted(sheets, key=lambda s: getattr(s, "Identification", getattr(s, "DocumentId", None))):
|
||||
|
||||
@@ -122,11 +122,10 @@ class TestAddBrickifcProject(NewFile):
|
||||
result = subject.add_brickifc_project("http://example.org/digitaltwin#")
|
||||
assert result == f"http://example.org/digitaltwin#{project.GlobalId}"
|
||||
brick = URIRef(result)
|
||||
props = tool.Blender.get_bim_props()
|
||||
assert list(BrickStore.graph.triples((brick, A, REF.ifcProject)))
|
||||
assert list(BrickStore.graph.triples((brick, REF.ifcProjectID, Literal(project.GlobalId))))
|
||||
assert list(
|
||||
BrickStore.graph.triples((brick, REF.ifcFileLocation, Literal(bpy.context.scene.BIMProperties.ifc_file)))
|
||||
)
|
||||
assert list(BrickStore.graph.triples((brick, REF.ifcFileLocation, Literal(props.ifc_file))))
|
||||
assert list(
|
||||
BrickStore.graph.triples(
|
||||
(brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("My Project"))
|
||||
|
||||
@@ -55,7 +55,8 @@ class TestLoadExpress(NewFile):
|
||||
|
||||
class TestPurgeHdf5Cache(NewFile):
|
||||
def test_run(self):
|
||||
cache_dir = Path(bpy.context.scene.BIMProperties.cache_dir)
|
||||
props = tool.Blender.get_bim_props()
|
||||
cache_dir = Path(props.cache_dir)
|
||||
test_file = cache_dir / "test.h5"
|
||||
test_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
test_file.touch()
|
||||
|
||||
@@ -36,13 +36,13 @@ class TestAddBreadcrumb(NewFile):
|
||||
tool.Ifc().set(ifc)
|
||||
document = ifc.createIfcDocumentInformation()
|
||||
subject.add_breadcrumb(document)
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
assert props.breadcrumbs[0].name == str(document.id())
|
||||
|
||||
|
||||
class TestClearBreadcrumbs(NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
props.breadcrumbs.add()
|
||||
subject.clear_breadcrumbs()
|
||||
assert len(props.breadcrumbs) == 0
|
||||
@@ -50,7 +50,7 @@ class TestClearBreadcrumbs(NewFile):
|
||||
|
||||
class TestClearDocumentTree(NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
new = props.documents.add()
|
||||
subject.clear_document_tree()
|
||||
assert len(props.documents) == 0
|
||||
@@ -58,23 +58,26 @@ class TestClearDocumentTree(NewFile):
|
||||
|
||||
class TestDisableEditingDocument(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMDocumentProperties.active_document_id = 1
|
||||
props = tool.Document.get_document_props()
|
||||
props.active_document_id = 1
|
||||
subject.disable_editing_document()
|
||||
assert bpy.context.scene.BIMDocumentProperties.active_document_id == 0
|
||||
assert props.active_document_id == 0
|
||||
|
||||
|
||||
class TestDisableEditingUI(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMDocumentProperties.is_editing = True
|
||||
props = tool.Document.get_document_props()
|
||||
props.is_editing = True
|
||||
subject.disable_editing_ui()
|
||||
assert bpy.context.scene.BIMDocumentProperties.is_editing == False
|
||||
assert props.is_editing == False
|
||||
|
||||
|
||||
class TestEnableEditingUI(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMDocumentProperties.is_editing = False
|
||||
props = tool.Document.get_document_props()
|
||||
props.is_editing = False
|
||||
subject.enable_editing_ui()
|
||||
assert bpy.context.scene.BIMDocumentProperties.is_editing == True
|
||||
assert props.is_editing == True
|
||||
|
||||
|
||||
class TestExportDocumentAttributes(NewFile):
|
||||
@@ -129,22 +132,22 @@ class TestImportDocumentAttributes(NewFile):
|
||||
document.Confidentiality = "CONFIDENTIAL"
|
||||
document.Status = "DRAFT"
|
||||
subject().import_document_attributes(document)
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
assert props.document_attributes.get("Identification").string_value == "Identification"
|
||||
assert props.document_attributes.get("Name").string_value == "Name"
|
||||
assert props.document_attributes.get("Description").string_value == "Description"
|
||||
assert props.document_attributes.get("Location").string_value == "Location"
|
||||
assert props.document_attributes.get("Purpose").string_value == "Purpose"
|
||||
assert props.document_attributes.get("IntendedUse").string_value == "IntendedUse"
|
||||
assert props.document_attributes.get("Scope").string_value == "Scope"
|
||||
assert props.document_attributes.get("Revision").string_value == "Revision"
|
||||
assert props.document_attributes.get("CreationTime").string_value == "CreationTime"
|
||||
assert props.document_attributes.get("LastRevisionTime").string_value == "LastRevisionTime"
|
||||
assert props.document_attributes.get("ElectronicFormat").string_value == "ElectronicFormat"
|
||||
assert props.document_attributes.get("ValidFrom").string_value == "ValidFrom"
|
||||
assert props.document_attributes.get("ValidUntil").string_value == "ValidUntil"
|
||||
assert props.document_attributes.get("Confidentiality").enum_value == "CONFIDENTIAL"
|
||||
assert props.document_attributes.get("Status").enum_value == "DRAFT"
|
||||
props = tool.Document.get_document_props()
|
||||
assert props.document_attributes["Identification"].string_value == "Identification"
|
||||
assert props.document_attributes["Name"].string_value == "Name"
|
||||
assert props.document_attributes["Description"].string_value == "Description"
|
||||
assert props.document_attributes["Location"].string_value == "Location"
|
||||
assert props.document_attributes["Purpose"].string_value == "Purpose"
|
||||
assert props.document_attributes["IntendedUse"].string_value == "IntendedUse"
|
||||
assert props.document_attributes["Scope"].string_value == "Scope"
|
||||
assert props.document_attributes["Revision"].string_value == "Revision"
|
||||
assert props.document_attributes["CreationTime"].string_value == "CreationTime"
|
||||
assert props.document_attributes["LastRevisionTime"].string_value == "LastRevisionTime"
|
||||
assert props.document_attributes["ElectronicFormat"].string_value == "ElectronicFormat"
|
||||
assert props.document_attributes["ValidFrom"].string_value == "ValidFrom"
|
||||
assert props.document_attributes["ValidUntil"].string_value == "ValidUntil"
|
||||
assert props.document_attributes["Confidentiality"].enum_value == "CONFIDENTIAL"
|
||||
assert props.document_attributes["Status"].enum_value == "DRAFT"
|
||||
|
||||
def test_importing_reference(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -155,11 +158,11 @@ class TestImportDocumentAttributes(NewFile):
|
||||
document.Name = "Name"
|
||||
document.Description = "Description"
|
||||
subject().import_document_attributes(document)
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
assert props.document_attributes.get("Location").string_value == "Location"
|
||||
assert props.document_attributes.get("Identification").string_value == "Identification"
|
||||
assert props.document_attributes.get("Name").string_value == "Name"
|
||||
assert props.document_attributes.get("Description").string_value == "Description"
|
||||
props = tool.Document.get_document_props()
|
||||
assert props.document_attributes["Location"].string_value == "Location"
|
||||
assert props.document_attributes["Identification"].string_value == "Identification"
|
||||
assert props.document_attributes["Name"].string_value == "Name"
|
||||
assert props.document_attributes["Description"].string_value == "Description"
|
||||
|
||||
|
||||
class TestImportProjectDocuments(NewFile):
|
||||
@@ -169,7 +172,7 @@ class TestImportProjectDocuments(NewFile):
|
||||
ifc.createIfcProject()
|
||||
document = ifcopenshell.api.run("document.add_information", ifc)
|
||||
subject.import_project_documents()
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
assert len(props.documents) == 1
|
||||
assert props.documents[0].ifc_definition_id == document.id()
|
||||
assert props.documents[0].name == "Unnamed"
|
||||
@@ -185,7 +188,7 @@ class TestImportReferences(NewFile):
|
||||
document = ifcopenshell.api.run("document.add_information", ifc)
|
||||
reference = ifcopenshell.api.run("document.add_reference", ifc, information=document)
|
||||
subject.import_references(document)
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
assert len(props.documents) == 1
|
||||
assert props.documents[0].ifc_definition_id == reference.id()
|
||||
assert props.documents[0].name == "Unnamed"
|
||||
@@ -201,7 +204,7 @@ class TestImportSubdocuments(NewFile):
|
||||
document = ifcopenshell.api.run("document.add_information", ifc)
|
||||
subdocument = ifcopenshell.api.run("document.add_information", ifc, parent=document)
|
||||
subject.import_subdocuments(document)
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
assert len(props.documents) == 1
|
||||
assert props.documents[0].ifc_definition_id == subdocument.id()
|
||||
assert props.documents[0].name == "Unnamed"
|
||||
@@ -220,7 +223,7 @@ class TestIsDocumentInformation(NewFile):
|
||||
|
||||
class TestRemoveLatestBreadcrumb(NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
props = tool.Document.get_document_props()
|
||||
props.breadcrumbs.add()
|
||||
props.breadcrumbs.add()
|
||||
subject.remove_latest_breadcrumb()
|
||||
@@ -232,4 +235,5 @@ class TestSetActiveDocument(NewFile):
|
||||
ifc = ifcopenshell.file()
|
||||
document = ifc.createIfcDocumentInformation()
|
||||
subject.set_active_document(document)
|
||||
assert bpy.context.scene.BIMDocumentProperties.active_document_id == document.id()
|
||||
props = tool.Document.get_document_props()
|
||||
assert props.active_document_id == document.id()
|
||||
|
||||
@@ -40,12 +40,14 @@ class TestSet(test.bim.bootstrap.NewFile):
|
||||
class TestGet(test.bim.bootstrap.NewFile):
|
||||
def test_getting_an_ifc_dataset_from_a_ifc_spf_filepath(self):
|
||||
assert subject.get() is None
|
||||
bpy.context.scene.BIMProperties.ifc_file = "test/files/basic.ifc"
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.ifc_file = "test/files/basic.ifc"
|
||||
result = subject.get()
|
||||
assert isinstance(result, ifcopenshell.file)
|
||||
|
||||
def test_getting_the_active_ifc_dataset_regardless_of_ifc_path(self):
|
||||
bpy.context.scene.BIMProperties.ifc_file = "test/files/basic.ifc"
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.ifc_file = "test/files/basic.ifc"
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
assert subject.get() == ifc
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.project
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.unit
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from test.bim.bootstrap import NewFile
|
||||
@@ -31,23 +34,26 @@ class TestImplementsTool(NewFile):
|
||||
|
||||
class TestClearActiveUnit(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMUnitProperties.active_unit_id = 1
|
||||
props = tool.Unit.get_unit_props()
|
||||
props.active_unit_id = 1
|
||||
subject.clear_active_unit()
|
||||
assert bpy.context.scene.BIMUnitProperties.active_unit_id == 0
|
||||
assert props.active_unit_id == 0
|
||||
|
||||
|
||||
class TestDisableEditingUnits(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMUnitProperties.is_editing = True
|
||||
props = tool.Unit.get_unit_props()
|
||||
props.is_editing = True
|
||||
subject.disable_editing_units()
|
||||
assert bpy.context.scene.BIMUnitProperties.is_editing == False
|
||||
assert props.is_editing == False
|
||||
|
||||
|
||||
class TestEnableEditingUnits(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMUnitProperties.is_editing = False
|
||||
props = tool.Unit.get_unit_props()
|
||||
props.is_editing = False
|
||||
subject.enable_editing_units()
|
||||
assert bpy.context.scene.BIMUnitProperties.is_editing == True
|
||||
assert props.is_editing == True
|
||||
|
||||
|
||||
class TestExportUnitAttributes(NewFile):
|
||||
@@ -98,10 +104,11 @@ class TestExportUnitAttributes(NewFile):
|
||||
|
||||
class TestGetSceneUnitName(NewFile):
|
||||
def test_getting_an_imperial_name(self):
|
||||
props = tool.Blender.get_bim_props()
|
||||
bpy.context.scene.unit_settings.system = "IMPERIAL"
|
||||
bpy.context.scene.unit_settings.length_unit = "MILES"
|
||||
bpy.context.scene.BIMProperties.area_unit = "square foot"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "cubic inch"
|
||||
props.area_unit = "square foot"
|
||||
props.volume_unit = "cubic inch"
|
||||
assert subject.get_scene_unit_name("LENGTHUNIT") == "mile"
|
||||
assert subject.get_scene_unit_name("AREAUNIT") == "square foot"
|
||||
assert subject.get_scene_unit_name("VOLUMEUNIT") == "cubic inch"
|
||||
@@ -142,13 +149,14 @@ class TestGetSceneUnitSIPrefix:
|
||||
assert subject.get_scene_unit_si_prefix("LENGTHUNIT") == "KILO"
|
||||
bpy.context.scene.unit_settings.length_unit = "ADAPTIVE"
|
||||
assert subject.get_scene_unit_si_prefix("LENGTHUNIT") is None
|
||||
bpy.context.scene.BIMProperties.area_unit = "SQUARE_METRE"
|
||||
props = tool.Blender.get_bim_props()
|
||||
props.area_unit = "SQUARE_METRE"
|
||||
assert subject.get_scene_unit_si_prefix("AREAUNIT") is None
|
||||
bpy.context.scene.BIMProperties.area_unit = "MILLI/SQUARE_METRE"
|
||||
props.area_unit = "MILLI/SQUARE_METRE"
|
||||
assert subject.get_scene_unit_si_prefix("AREAUNIT") == "MILLI"
|
||||
bpy.context.scene.BIMProperties.volume_unit = "CUBIC_METRE"
|
||||
props.volume_unit = "CUBIC_METRE"
|
||||
assert subject.get_scene_unit_si_prefix("VOLUMEUNIT") is None
|
||||
bpy.context.scene.BIMProperties.volume_unit = "MILLI/CUBIC_METRE"
|
||||
props.volume_unit = "MILLI/CUBIC_METRE"
|
||||
assert subject.get_scene_unit_si_prefix("VOLUMEUNIT") == "MILLI"
|
||||
|
||||
|
||||
@@ -159,25 +167,25 @@ class TestImportUnitAttributes(NewFile):
|
||||
unit.UnitType = "ANGULARVELOCITYUNIT"
|
||||
unit.UserDefinedType = "UserDefinedType"
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("UnitType").enum_value == "ANGULARVELOCITYUNIT"
|
||||
assert props.unit_attributes.get("UserDefinedType").string_value == "UserDefinedType"
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ANGULARVELOCITYUNIT"
|
||||
assert props.unit_attributes["UserDefinedType"].string_value == "UserDefinedType"
|
||||
|
||||
def test_importing_monetary_units(self):
|
||||
tool.Ifc.set(ifc := ifcopenshell.file())
|
||||
unit = ifc.createIfcMonetaryUnit()
|
||||
unit.Currency = "Currency"
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("Currency").string_value == "Currency"
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["Currency"].string_value == "Currency"
|
||||
|
||||
def test_importing_monetary_units_ifc2x3(self):
|
||||
tool.Ifc.set(ifc := ifcopenshell.file(schema="IFC2X3"))
|
||||
unit = ifc.createIfcMonetaryUnit()
|
||||
unit.Currency = "USD"
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("Currency").enum_value == "USD"
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["Currency"].enum_value == "USD"
|
||||
|
||||
def test_importing_context_dependent_units(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -187,10 +195,10 @@ class TestImportUnitAttributes(NewFile):
|
||||
unit.Name = "Name"
|
||||
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes["Name"].string_value == "Name"
|
||||
assert props.unit_attributes["Dimensions"].string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
|
||||
def test_importing_conversion_based_units(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -200,10 +208,10 @@ class TestImportUnitAttributes(NewFile):
|
||||
unit.Name = "Name"
|
||||
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes["Name"].string_value == "Name"
|
||||
assert props.unit_attributes["Dimensions"].string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
|
||||
def test_importing_conversion_based_with_offset_units(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -214,11 +222,11 @@ class TestImportUnitAttributes(NewFile):
|
||||
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||
unit.ConversionOffset = 1
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
assert props.unit_attributes.get("ConversionOffset").float_value == 1
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes["Name"].string_value == "Name"
|
||||
assert props.unit_attributes["Dimensions"].string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||
assert props.unit_attributes["ConversionOffset"].float_value == 1
|
||||
|
||||
def test_importing_si_units(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -228,11 +236,11 @@ class TestImportUnitAttributes(NewFile):
|
||||
unit.Prefix = "EXA"
|
||||
unit.Name = "AMPERE"
|
||||
subject.import_unit_attributes(unit)
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes.get("Prefix").enum_value == "EXA"
|
||||
assert props.unit_attributes.get("Name").enum_value == "AMPERE"
|
||||
assert props.unit_attributes.get("Dimensions") is None
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes["Prefix"].enum_value == "EXA"
|
||||
assert props.unit_attributes["Name"].enum_value == "AMPERE"
|
||||
assert props.unit_attributes["Dimensions"] is None
|
||||
|
||||
|
||||
class TestImportUnits(NewFile):
|
||||
@@ -248,7 +256,7 @@ class TestImportUnits(NewFile):
|
||||
ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcProject")
|
||||
ifcopenshell.api.unit.assign_unit(ifc, units=[unit2])
|
||||
subject.import_units()
|
||||
props = bpy.context.scene.BIMUnitProperties
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert len(props.units) == 6
|
||||
|
||||
assert props.units[0].ifc_definition_id == unit1.id()
|
||||
@@ -311,4 +319,5 @@ class TestSetActiveUnit(NewFile):
|
||||
ifc = ifcopenshell.file()
|
||||
unit = ifc.createIfcSIUnit()
|
||||
subject.set_active_unit(unit)
|
||||
assert bpy.context.scene.BIMUnitProperties.active_unit_id == unit.id()
|
||||
props = tool.Unit.get_unit_props()
|
||||
assert props.active_unit_id == unit.id()
|
||||
|
||||
@@ -62,42 +62,38 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
# No we don't.
|
||||
ifcopenshell.api.root.remove_product(model, product=wall)
|
||||
"""
|
||||
settings = {"product": product}
|
||||
|
||||
representations = []
|
||||
if settings["product"].is_a("IfcProduct"):
|
||||
if settings["product"].Representation:
|
||||
representations = settings["product"].Representation.Representations or []
|
||||
representations: list[ifcopenshell.entity_instance] = []
|
||||
if product.is_a("IfcProduct"):
|
||||
if product.Representation:
|
||||
representations = product.Representation.Representations or []
|
||||
else:
|
||||
representations = []
|
||||
|
||||
# remove object placements
|
||||
object_placement = settings["product"].ObjectPlacement
|
||||
object_placement = product.ObjectPlacement
|
||||
if object_placement:
|
||||
if file.get_total_inverses(object_placement) == 1:
|
||||
settings["product"].ObjectPlacement = None # remove the inverse for remove_deep2 to work
|
||||
product.ObjectPlacement = None # remove the inverse for remove_deep2 to work
|
||||
ifcopenshell.util.element.remove_deep2(file, object_placement)
|
||||
|
||||
elif settings["product"].is_a("IfcTypeProduct"):
|
||||
representations = [rm.MappedRepresentation for rm in settings["product"].RepresentationMaps or []]
|
||||
elif product.is_a("IfcTypeProduct"):
|
||||
representations = [rm.MappedRepresentation for rm in product.RepresentationMaps or []]
|
||||
|
||||
# remove psets
|
||||
psets = settings["product"].HasPropertySets or []
|
||||
psets = product.HasPropertySets or []
|
||||
for pset in psets:
|
||||
if file.get_total_inverses(pset) != 1:
|
||||
continue
|
||||
ifcopenshell.api.pset.remove_pset(file, product=settings["product"], pset=pset)
|
||||
ifcopenshell.api.pset.remove_pset(file, product=product, pset=pset)
|
||||
|
||||
for representation in representations:
|
||||
ifcopenshell.api.geometry.unassign_representation(
|
||||
file, product=settings["product"], representation=representation
|
||||
)
|
||||
ifcopenshell.api.geometry.remove_representation(file, **{"representation": representation})
|
||||
for opening in getattr(settings["product"], "HasOpenings", []) or []:
|
||||
ifcopenshell.api.geometry.unassign_representation(file, product=product, representation=representation)
|
||||
ifcopenshell.api.geometry.remove_representation(file, representation=representation)
|
||||
for opening in getattr(product, "HasOpenings", []) or []:
|
||||
ifcopenshell.api.feature.remove_feature(file, feature=opening.RelatedOpeningElement)
|
||||
|
||||
if settings["product"].is_a("IfcGrid"):
|
||||
for axis in settings["product"].UAxes + settings["product"].VAxes + (settings["product"].WAxes or ()):
|
||||
if product.is_a("IfcGrid"):
|
||||
for axis in product.UAxes + product.VAxes + (product.WAxes or ()):
|
||||
ifcopenshell.api.grid.remove_grid_axis(file, axis=axis)
|
||||
|
||||
def element_exists(element_id):
|
||||
@@ -108,22 +104,20 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
return False
|
||||
|
||||
# TODO: remove object placement and other relationships
|
||||
for inverse_id in [i.id() for i in file.get_inverse(settings["product"])]:
|
||||
for inverse_id in [i.id() for i in file.get_inverse(product)]:
|
||||
try:
|
||||
inverse = file.by_id(inverse_id)
|
||||
except:
|
||||
continue
|
||||
if inverse.is_a("IfcRelDefinesByProperties"):
|
||||
ifcopenshell.api.pset.remove_pset(
|
||||
file, product=settings["product"], pset=inverse.RelatingPropertyDefinition
|
||||
)
|
||||
ifcopenshell.api.pset.remove_pset(file, product=product, pset=inverse.RelatingPropertyDefinition)
|
||||
elif inverse.is_a("IfcRelAssociatesMaterial"):
|
||||
ifcopenshell.api.material.unassign_material(file, products=[settings["product"]])
|
||||
ifcopenshell.api.material.unassign_material(file, products=[product])
|
||||
elif inverse.is_a("IfcRelDefinesByType"):
|
||||
if inverse.RelatingType == settings["product"]:
|
||||
if inverse.RelatingType == product:
|
||||
ifcopenshell.api.type.unassign_type(file, related_objects=inverse.RelatedObjects)
|
||||
else:
|
||||
ifcopenshell.api.type.unassign_type(file, related_objects=[settings["product"]])
|
||||
ifcopenshell.api.type.unassign_type(file, related_objects=[product])
|
||||
elif inverse.is_a("IfcRelSpaceBoundary"):
|
||||
ifcopenshell.api.boundary.remove_boundary(file, boundary=inverse)
|
||||
elif inverse.is_a("IfcRelFillsElement"):
|
||||
@@ -142,7 +136,7 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelNests"):
|
||||
if inverse.RelatingObject == settings["product"]:
|
||||
if inverse.RelatingObject == product:
|
||||
inverse_id = inverse.id()
|
||||
for subelement in inverse.RelatedObjects:
|
||||
if subelement.is_a("IfcDistributionPort"):
|
||||
@@ -153,27 +147,27 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.RelatedObjects == (settings["product"],):
|
||||
elif inverse.RelatedObjects == (product,):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelAggregates"):
|
||||
if inverse.RelatingObject == settings["product"] or len(inverse.RelatedObjects) == 1:
|
||||
if inverse.RelatingObject == product or len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelContainedInSpatialStructure"):
|
||||
if inverse.RelatingStructure == settings["product"] or len(inverse.RelatedElements) == 1:
|
||||
if inverse.RelatingStructure == product or len(inverse.RelatedElements) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelConnectsElements"):
|
||||
if inverse.is_a("IfcRelConnectsWithRealizingElements"):
|
||||
if settings["product"] not in (inverse.RelatingElement, inverse.RelatedElement) and any(
|
||||
el for el in inverse.RealizingElements if el != settings["product"]
|
||||
if product not in (inverse.RelatingElement, inverse.RelatedElement) and any(
|
||||
el for el in inverse.RealizingElements if el != product
|
||||
):
|
||||
continue
|
||||
history = inverse.OwnerHistory
|
||||
@@ -181,15 +175,15 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelConnectsPortToElement"):
|
||||
if inverse.RelatedElement == settings["product"]:
|
||||
if inverse.RelatedElement == product:
|
||||
ifcopenshell.api.root.remove_product(file, product=inverse.RelatingPort)
|
||||
elif inverse.RelatingPort == settings["product"]:
|
||||
elif inverse.RelatingPort == product:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelConnectsPorts"):
|
||||
if settings["product"] not in (inverse.RelatingPort, inverse.RelatedPort):
|
||||
if product not in (inverse.RelatingPort, inverse.RelatedPort):
|
||||
# if it's not RelatingPort/RelatedPort then it's optional RealizingElement
|
||||
# so we keep the relationship
|
||||
continue
|
||||
@@ -204,7 +198,7 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelAssignsToProduct"):
|
||||
if inverse.RelatingProduct == settings["product"]:
|
||||
if inverse.RelatingProduct == product:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
@@ -215,17 +209,17 @@ def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instanc
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelFlowControlElements"):
|
||||
if inverse.RelatingFlowElement == settings["product"]:
|
||||
if inverse.RelatingFlowElement == product:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.RelatedControlElements == (settings["product"],):
|
||||
elif inverse.RelatedControlElements == (product,):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
history = settings["product"].OwnerHistory
|
||||
file.remove(settings["product"])
|
||||
history = product.OwnerHistory
|
||||
file.remove(product)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
@@ -81,7 +81,7 @@ class Usecase:
|
||||
def execute(self, style: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
self.style = style
|
||||
|
||||
attribute_types = {}
|
||||
attribute_types: dict[str, str] = {}
|
||||
for attribute in style.wrapped_data.declaration().as_entity().all_attributes():
|
||||
attribute_type = attribute.type_of_attribute()
|
||||
if attribute_type.as_aggregation_type() is None:
|
||||
|
||||
@@ -248,14 +248,10 @@ class entity_instance:
|
||||
|
||||
:param f: A callable that takes a single argument and returns a boolean
|
||||
value. It represents the condition.
|
||||
:type f: Callable
|
||||
:param g: A callable that takes a single argument and returns a
|
||||
transformed value. It represents the transformation.
|
||||
:type g: Callable
|
||||
:param value: Any object, the input value to be processed
|
||||
:type value: Any
|
||||
:return: Transformed value
|
||||
:rtype: Any
|
||||
|
||||
Example:
|
||||
|
||||
@@ -304,8 +300,6 @@ class entity_instance:
|
||||
"""Return the data type of a positional attribute of the element
|
||||
|
||||
:param attr: The index or name of the attribute
|
||||
:type attr: Union[int, str]
|
||||
:rtype: string
|
||||
"""
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
@@ -314,8 +308,6 @@ class entity_instance:
|
||||
"""Return the name of a positional attribute of the element
|
||||
|
||||
:param attr_idx: The index of the attribute
|
||||
:type attr_idx: int
|
||||
:rtype: string
|
||||
"""
|
||||
return self.wrapped_data.get_argument_name(attr_idx)
|
||||
|
||||
@@ -405,9 +397,7 @@ class entity_instance:
|
||||
returned IFC class name should include schema name
|
||||
(e.g. "IFC4.IfcWall" if `True` and "IfcWall" if `False`).
|
||||
If omitted will act as `False`.
|
||||
:type args: Union[str, bool]
|
||||
:returns: Either the name of the class, or a boolean if it passes the check
|
||||
:rtype: Union[str, bool]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -423,10 +413,7 @@ class entity_instance:
|
||||
return self.wrapped_data.is_a(*args)
|
||||
|
||||
def id(self) -> int:
|
||||
"""Return the STEP numerical identifier
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
"""Return the STEP numerical identifier"""
|
||||
return self.wrapped_data.id()
|
||||
|
||||
def __eq__(self, other: "entity_instance") -> bool:
|
||||
|
||||
@@ -359,7 +359,6 @@ class file:
|
||||
of those methods.
|
||||
|
||||
:param type: Case insensitive name of the IFC class
|
||||
:type type: string
|
||||
:param args: The positional arguments of the IFC class
|
||||
:param kwargs: The keyword arguments of the IFC class
|
||||
:returns: An entity instance
|
||||
@@ -482,12 +481,10 @@ class file:
|
||||
"""Return an IFC entity instance filtered by IFC ID.
|
||||
|
||||
:param id: STEP numerical identifier
|
||||
:type id: int
|
||||
|
||||
:raises RuntimeError: If `id` is not found.
|
||||
|
||||
:returns: An ifcopenshell.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
return self[id]
|
||||
|
||||
@@ -495,13 +492,10 @@ class file:
|
||||
"""Return an IFC entity instance filtered by IFC GUID.
|
||||
|
||||
:param guid: GlobalId value in 22-character encoded form
|
||||
:type guid: string
|
||||
|
||||
:raises RuntimeError: If `guid` is not found.
|
||||
|
||||
:returns: An ifcopenshell.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
"""
|
||||
return self[guid]
|
||||
|
||||
@@ -510,9 +504,7 @@ class file:
|
||||
If the entity already exists, it is not re-added. Existence of entity is checked by it's `.identity()`.
|
||||
|
||||
:param inst: The entity instance to add
|
||||
:type inst: ifcopenshell.entity_instance
|
||||
:returns: An ifcopenshell.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
|
||||
if self.transaction:
|
||||
@@ -530,14 +522,11 @@ class file:
|
||||
If an IFC type class has subclasses, all entities of those subclasses are also returned.
|
||||
|
||||
:param type: The case insensitive type of IFC class to return.
|
||||
:type type: string
|
||||
:param include_subtypes: Whether or not to return subtypes of the IFC class
|
||||
:type include_subtypes: bool
|
||||
|
||||
:raises RuntimeError: If `type` is not found in IFC schema.
|
||||
|
||||
:returns: A list of ifcopenshell.entity_instance objects
|
||||
:rtype: list[ifcopenshell.entity_instance]
|
||||
"""
|
||||
if include_subtypes:
|
||||
return [entity_instance(e, self) for e in self.wrapped_data.by_type(type)]
|
||||
@@ -625,9 +614,7 @@ class file:
|
||||
significantly faster.
|
||||
|
||||
:param inst: The entity instance to get inverse relationships
|
||||
:type inst: ifcopenshell.entity_instance
|
||||
:returns: The total number of references
|
||||
:rtype: int
|
||||
"""
|
||||
return self.wrapped_data.get_total_inverses(inst.wrapped_data)
|
||||
|
||||
@@ -639,8 +626,6 @@ class file:
|
||||
the reference to the deleted will be removed from the aggregate.
|
||||
|
||||
:param inst: The entity instance to delete
|
||||
:type inst: ifcopenshell.entity_instance
|
||||
:rtype: None
|
||||
"""
|
||||
if self.transaction:
|
||||
self.transaction.store_delete(inst)
|
||||
@@ -676,9 +661,7 @@ class file:
|
||||
if None. Supported formats : .ifc, .ifcXML, .ifcZIP (equivalent to
|
||||
format=".ifc" with zipped=True) For zipped .ifcXML use
|
||||
format=".ifcXML" with zipped=True
|
||||
:type format: str
|
||||
:param zipped: zip the file after it is written
|
||||
:type zipped: bool
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user