mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 21:59:59 +00:00
Merge branch 'v0.8.0' of https://github.com/IfcOpenShell/IfcOpenShell into v0.8.0
This commit is contained in:
@@ -317,6 +317,12 @@ endif
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Temporary workaround for Blender not handling non-3.11 wheels #5743.
|
||||||
|
# Use '-n' as on macos x86-64 doesn't have a binary wheel and it autoincludes 'cp311'.
|
||||||
|
prev_whl_name=$$(find build/bonsai/wheels/tzfpy-*.whl); \
|
||||||
|
whl_name=$$(echo $$prev_whl_name | sed "s/-cp39-/-cp$(PYNUMBER)-/"); \
|
||||||
|
mv -n "$$prev_whl_name" "$$whl_name";
|
||||||
|
|
||||||
ifneq ($(PLATFORM), linux)
|
ifneq ($(PLATFORM), linux)
|
||||||
# Safeguard: in case one of `pip download` will break,
|
# Safeguard: in case one of `pip download` will break,
|
||||||
# it will produce a linux wheel for non-linux build (our github action machine is using linux).
|
# it will produce a linux wheel for non-linux build (our github action machine is using linux).
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import bpy
|
|||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import traceback
|
||||||
import mathutils
|
import mathutils
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
@@ -843,14 +844,46 @@ class IfcImporter:
|
|||||||
curve = bpy.data.curves.new(mesh_name, type="CURVE")
|
curve = bpy.data.curves.new(mesh_name, type="CURVE")
|
||||||
curve.dimensions = "3D"
|
curve.dimensions = "3D"
|
||||||
curve.resolution_u = 2
|
curve.resolution_u = 2
|
||||||
polyline = curve.splines.new("POLY")
|
|
||||||
|
|
||||||
for item_data in ifcopenshell.util.representation.resolve_items(native_data["representation"]):
|
rep_items = ifcopenshell.util.representation.resolve_items(native_data["representation"])
|
||||||
|
|
||||||
|
# Find item styles and add them to the curve.
|
||||||
|
material_style = None
|
||||||
|
material = ifcopenshell.util.element.get_material(element)
|
||||||
|
if material:
|
||||||
|
material_style = tool.Material.get_style(material)
|
||||||
|
item_styles: list[Union[bpy.types.Material, None]] = []
|
||||||
|
for item_data in rep_items:
|
||||||
item = item_data["item"]
|
item = item_data["item"]
|
||||||
|
item_style = tool.Style.get_representation_item_style(item) or material_style
|
||||||
|
if item_style is not None:
|
||||||
|
item_style = tool.Ifc.get_object(item_style)
|
||||||
|
assert isinstance(item_style, bpy.types.Material)
|
||||||
|
item_styles.append(item_style)
|
||||||
|
item_styles_unique = list(set(item_styles))
|
||||||
|
for item_style in item_styles_unique:
|
||||||
|
curve.materials.append(item_style)
|
||||||
|
use_same_material_index = len(item_styles_unique) < 2
|
||||||
|
|
||||||
|
def new_polyline(item_style: Union[bpy.types.Material, None]) -> bpy.types.Spline:
|
||||||
|
if use_same_material_index:
|
||||||
|
material_index = 0
|
||||||
|
else:
|
||||||
|
material_index = item_styles_unique.index(item_style)
|
||||||
|
|
||||||
|
polyline = curve.splines.new("POLY")
|
||||||
|
polyline.material_index = material_index
|
||||||
|
return polyline
|
||||||
|
|
||||||
|
for item_data, item_style in zip(rep_items, item_styles):
|
||||||
|
item = item_data["item"]
|
||||||
|
|
||||||
|
polyline = new_polyline(item_style)
|
||||||
matrix = item_data["matrix"]
|
matrix = item_data["matrix"]
|
||||||
matrix[0][3] *= self.unit_scale
|
matrix[0][3] *= self.unit_scale
|
||||||
matrix[1][3] *= self.unit_scale
|
matrix[1][3] *= self.unit_scale
|
||||||
matrix[2][3] *= self.unit_scale
|
matrix[2][3] *= self.unit_scale
|
||||||
|
|
||||||
# TODO: support inner radius, start param, and end param
|
# TODO: support inner radius, start param, and end param
|
||||||
geometry = tool.Loader.create_generic_shape(item.Directrix)
|
geometry = tool.Loader.create_generic_shape(item.Directrix)
|
||||||
if not geometry:
|
if not geometry:
|
||||||
@@ -863,7 +896,7 @@ class IfcImporter:
|
|||||||
for edge in edges:
|
for edge in edges:
|
||||||
v1 = vertices[edge[0]]
|
v1 = vertices[edge[0]]
|
||||||
if v1 != v2:
|
if v1 != v2:
|
||||||
polyline = curve.splines.new("POLY")
|
polyline = new_polyline(item_style)
|
||||||
polyline.points[-1].co = native_data["matrix"] @ mathutils.Vector(v1)
|
polyline.points[-1].co = native_data["matrix"] @ mathutils.Vector(v1)
|
||||||
v2 = vertices[edge[1]]
|
v2 = vertices[edge[1]]
|
||||||
polyline.points.add(1)
|
polyline.points.add(1)
|
||||||
@@ -1060,11 +1093,7 @@ class IfcImporter:
|
|||||||
v2 = vertices[edge[1]]
|
v2 = vertices[edge[1]]
|
||||||
polyline.points.add(1)
|
polyline.points.add(1)
|
||||||
polyline.points[-1].co = mathutils.Vector(v2)
|
polyline.points[-1].co = mathutils.Vector(v2)
|
||||||
# TODO: remove error handling after we update build in Bonsai.
|
edges_item_ids = ifcopenshell.util.shape.get_edges_representation_item_ids(geometry).tolist()
|
||||||
try:
|
|
||||||
edges_item_ids = ifcopenshell.util.shape.get_edges_representation_item_ids(geometry).tolist()
|
|
||||||
except AttributeError:
|
|
||||||
edges_item_ids = []
|
|
||||||
curve["ios_edges_item_ids"] = edges_item_ids
|
curve["ios_edges_item_ids"] = edges_item_ids
|
||||||
return curve
|
return curve
|
||||||
|
|
||||||
@@ -1226,12 +1255,20 @@ class IfcImportSettings:
|
|||||||
settings.false_origin_mode = props.false_origin_mode
|
settings.false_origin_mode = props.false_origin_mode
|
||||||
try:
|
try:
|
||||||
settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]]
|
settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]]
|
||||||
except:
|
except Exception as e:
|
||||||
settings.false_origin = [0, 0, 0]
|
print(traceback.format_exc())
|
||||||
|
raise Exception(
|
||||||
|
f"Failed to set false origin from string '{props.false_origin}'.\n"
|
||||||
|
f"Error: {str(e)}.\nSee above for the details."
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
settings.project_north = float(props.project_north)
|
settings.project_north = float(props.project_north)
|
||||||
except:
|
except Exception as e:
|
||||||
settings.project_north = 0
|
print(traceback.format_exc())
|
||||||
|
raise Exception(
|
||||||
|
f"Failed to set project north from string '{props.project_north}'.\n"
|
||||||
|
f"Error: {str(e)}.\nSee above for the details."
|
||||||
|
)
|
||||||
settings.element_limit_mode = props.element_limit_mode
|
settings.element_limit_mode = props.element_limit_mode
|
||||||
settings.element_offset = props.element_offset
|
settings.element_offset = props.element_offset
|
||||||
settings.element_limit = props.element_limit
|
settings.element_limit = props.element_limit
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from . import ui, prop, operator, handler, gizmos, workspace
|
|||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.ActivateDrawing,
|
operator.ActivateDrawing,
|
||||||
|
operator.ActivateDrawingFromSheet,
|
||||||
operator.ActivateDrawingStyle,
|
operator.ActivateDrawingStyle,
|
||||||
operator.ActivateModel,
|
operator.ActivateModel,
|
||||||
operator.AddAnnotation,
|
operator.AddAnnotation,
|
||||||
@@ -52,6 +53,7 @@ classes = (
|
|||||||
operator.DisableEditingSheets,
|
operator.DisableEditingSheets,
|
||||||
operator.DisableEditingText,
|
operator.DisableEditingText,
|
||||||
operator.DuplicateDrawing,
|
operator.DuplicateDrawing,
|
||||||
|
operator.DuplicateSheet,
|
||||||
operator.EditAssignedProduct,
|
operator.EditAssignedProduct,
|
||||||
operator.EditElementFilter,
|
operator.EditElementFilter,
|
||||||
operator.EditSheet,
|
operator.EditSheet,
|
||||||
@@ -68,6 +70,7 @@ classes = (
|
|||||||
operator.LoadSchedules,
|
operator.LoadSchedules,
|
||||||
operator.LoadSheets,
|
operator.LoadSheets,
|
||||||
operator.OpenDrawing,
|
operator.OpenDrawing,
|
||||||
|
operator.OpenLayout,
|
||||||
operator.OpenReference,
|
operator.OpenReference,
|
||||||
operator.OpenSchedule,
|
operator.OpenSchedule,
|
||||||
operator.OpenSheet,
|
operator.OpenSheet,
|
||||||
@@ -86,6 +89,7 @@ classes = (
|
|||||||
operator.SaveDrawingStyle,
|
operator.SaveDrawingStyle,
|
||||||
operator.SaveDrawingStylesData,
|
operator.SaveDrawingStylesData,
|
||||||
operator.SelectAllDrawings,
|
operator.SelectAllDrawings,
|
||||||
|
operator.SelectAllSheets,
|
||||||
operator.SelectAssignedProduct,
|
operator.SelectAssignedProduct,
|
||||||
operator.SelectDocIfcFile,
|
operator.SelectDocIfcFile,
|
||||||
operator.OpenDocumentationWebUi,
|
operator.OpenDocumentationWebUi,
|
||||||
|
|||||||
@@ -154,10 +154,19 @@ class AddDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.duplicate_drawing"
|
bl_idname = "bim.duplicate_drawing"
|
||||||
bl_label = "Duplicate Drawing"
|
bl_label = "Duplicate Drawing"
|
||||||
|
bl_description = "Make a copy of currently selected drawing"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
drawing: bpy.props.IntProperty()
|
drawing: bpy.props.IntProperty()
|
||||||
should_duplicate_annotations: bpy.props.BoolProperty(name="Should Duplicate Annotations", default=False)
|
should_duplicate_annotations: bpy.props.BoolProperty(name="Should Duplicate Annotations", default=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return context.window_manager.invoke_props_dialog(self)
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
@@ -190,10 +199,16 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
bl_idname = "bim.create_drawing"
|
bl_idname = "bim.create_drawing"
|
||||||
bl_label = "Create Drawing"
|
bl_label = "Create Drawing"
|
||||||
bl_description = (
|
bl_description = (
|
||||||
"Creates/refreshes a .svg drawing based on currently active camera.\n\n"
|
"Creates/refreshes a .svg drawing based on currently active camera\n"
|
||||||
+ "SHIFT+CLICK to print all selected drawings"
|
+ 'and open with default system viewer or using "svg_command" or\n'
|
||||||
|
+ '"pdf_command" from the Bonsai preferences (if provided).\n\n'
|
||||||
|
+ "SHIFT+CLICK to create/refresh all shown checked drawings, but doesn't\n"
|
||||||
|
+ "open them for viewing.\n\n"
|
||||||
|
+ "Add the CTRL modifier to optionally open drawings to view them as\n"
|
||||||
|
+ "they are created"
|
||||||
)
|
)
|
||||||
print_all: bpy.props.BoolProperty(name="Print All", default=False, options={"SKIP_SAVE"})
|
print_all: bpy.props.BoolProperty(name="Print All", default=False, options={"SKIP_SAVE"})
|
||||||
|
open_viewer: bpy.props.BoolProperty(name="Open in Viewer", default=False, options={"SKIP_SAVE"})
|
||||||
sync: bpy.props.BoolProperty(
|
sync: bpy.props.BoolProperty(
|
||||||
name="Sync Before Creating Drawing",
|
name="Sync Before Creating Drawing",
|
||||||
description="Could save some time if you're sure IFC and current Blender session are already in sync",
|
description="Could save some time if you're sure IFC and current Blender session are already in sync",
|
||||||
@@ -223,6 +238,8 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
if event.type == "LEFTMOUSE" and event.shift:
|
if event.type == "LEFTMOUSE" and event.shift:
|
||||||
self.print_all = True
|
self.print_all = True
|
||||||
|
if event.type == "LEFTMOUSE" and event.ctrl:
|
||||||
|
self.open_viewer = True
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
@@ -291,8 +308,11 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
with profile("Combine SVG layers"):
|
with profile("Combine SVG layers"):
|
||||||
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
|
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
|
||||||
|
|
||||||
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg_path)
|
if self.open_viewer:
|
||||||
|
drawing_uri = tool.Drawing.get_document_uri(tool.Drawing.get_drawing_document(self.drawing))
|
||||||
|
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, drawing_uri)
|
||||||
|
if not self.open_viewer:
|
||||||
|
self.report({"INFO"}, f"{len(drawings_to_print)} drawings created...")
|
||||||
if self.print_all:
|
if self.print_all:
|
||||||
bpy.ops.bim.activate_drawing(drawing=original_drawing_id, should_view_from_camera=False)
|
bpy.ops.bim.activate_drawing(drawing=original_drawing_id, should_view_from_camera=False)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -1436,22 +1456,163 @@ class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
core.add_sheet(tool.Ifc, tool.Drawing, titleblock=context.scene.DocProperties.titleblock)
|
core.add_sheet(tool.Ifc, tool.Drawing, titleblock=context.scene.DocProperties.titleblock)
|
||||||
|
|
||||||
|
|
||||||
class OpenSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class DuplicateSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.open_sheet"
|
bl_idname = "bim.duplicate_sheet"
|
||||||
bl_label = "Open Sheet Layout"
|
bl_label = "Duplicate Sheet"
|
||||||
|
bl_description = "Make a copy of currently selected sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
drawing: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
# Unconditionally disable until implemented
|
||||||
|
cls.poll_message_set("Not implemented yet.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
self.props = context.scene.DocProperties
|
||||||
|
core.duplicate_sheet(
|
||||||
|
tool.Ifc,
|
||||||
|
tool.Drawing,
|
||||||
|
sheet=tool.Ifc.get().by_id(self.sheet),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
sheet = tool.Ifc.get().by_id(self.props.active_sheet_id)
|
||||||
|
core.sync_references(tool.Ifc, tool.Collector, tool.Sheet, drawing=sheet)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class OpenLayout(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.open_layout"
|
||||||
|
bl_label = "Open Sheet Layout"
|
||||||
|
bl_description = (
|
||||||
|
"Opens selected .svg layout with default system viewer\n"
|
||||||
|
+ 'or using "layout_svg_command" from the Bonsai preferences\n'
|
||||||
|
+ "(if provided)"
|
||||||
|
)
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
active_sheet = props.sheets[props.active_sheet_index]
|
||||||
|
if not active_sheet.is_sheet:
|
||||||
|
cls.poll_message_set("No sheet selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.props = context.scene.DocProperties
|
self.props = context.scene.DocProperties
|
||||||
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
||||||
sheet_builder = sheeter.SheetBuilder()
|
sheet_builder = sheeter.SheetBuilder()
|
||||||
sheet_builder.update_sheet_drawing_sizes(sheet)
|
sheet_builder.update_sheet_drawing_sizes(sheet)
|
||||||
core.open_sheet(tool.Drawing, sheet=sheet)
|
core.open_layout(tool.Drawing, sheet=sheet)
|
||||||
|
|
||||||
|
|
||||||
|
class SelectAllSheets(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.select_all_sheets"
|
||||||
|
bl_label = "Select All Sheetss"
|
||||||
|
view: bpy.props.StringProperty()
|
||||||
|
bl_description = "Select all sheets in the sheet list.\n\n" + "SHIFT+CLICK to deselect all sheets"
|
||||||
|
select_all: bpy.props.BoolProperty(name="Open All", default=True, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
# deselect all sheets on shift+click
|
||||||
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
|
if event.type == "LEFTMOUSE" and event.shift:
|
||||||
|
self.select_all = False
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for sheet in context.scene.DocProperties.sheets:
|
||||||
|
if sheet.is_selected != self.select_all:
|
||||||
|
sheet.is_selected = self.select_all
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class OpenSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.open_sheet"
|
||||||
|
bl_label = "Open Sheet"
|
||||||
|
bl_description = (
|
||||||
|
"Opens selected sheet with default system viewer\n"
|
||||||
|
+ 'or using "svg_command" or "pdf_command" from\n'
|
||||||
|
+ "the Bonsai preferences (if provided).\n\n"
|
||||||
|
+ "SHIFT+CLICK to open all shown checked sheets"
|
||||||
|
)
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
open_all: bpy.props.BoolProperty(name="Open All", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
active_sheet = props.sheets[props.active_sheet_index]
|
||||||
|
if not active_sheet.is_sheet:
|
||||||
|
cls.poll_message_set("No sheet selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
# opening all sheets on shift+click
|
||||||
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
|
if event.type == "LEFTMOUSE" and event.shift:
|
||||||
|
self.open_all = True
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.props = context.scene.DocProperties
|
||||||
|
svg2pdf_command = tool.Blender.get_addon_preferences().svg2pdf_command
|
||||||
|
|
||||||
|
if self.open_all:
|
||||||
|
sheets = [
|
||||||
|
tool.Ifc.get().by_id(s.ifc_definition_id) for s in self.props.sheets if s.is_sheet and s.is_selected
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
sheets = [tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)]
|
||||||
|
|
||||||
|
sheet_uris = []
|
||||||
|
sheets_not_found = []
|
||||||
|
|
||||||
|
for sheet in sheets:
|
||||||
|
if not sheet.is_a("IfcDocumentInformation"):
|
||||||
|
continue
|
||||||
|
sheet_builder = sheeter.SheetBuilder()
|
||||||
|
references = sheet_builder.build(sheet)
|
||||||
|
sheet_uri = references["SHEET"]
|
||||||
|
if svg2pdf_command:
|
||||||
|
sheet_uri = os.path.splitext(sheet_uri)[0] + ".pdf"
|
||||||
|
sheet_uris.append(sheet_uri)
|
||||||
|
if not os.path.exists(sheet_uri):
|
||||||
|
sheets_not_found.append(sheet.Name)
|
||||||
|
|
||||||
|
if sheets_not_found:
|
||||||
|
msg = "Some sheets .svg/.pdf files were not found, need to create them first: \n{}.".format(
|
||||||
|
"\n".join(sheets_not_found)
|
||||||
|
)
|
||||||
|
self.report({"ERROR"}, msg)
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
for sheet_uri in sheet_uris:
|
||||||
|
if svg2pdf_command:
|
||||||
|
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, sheet_uri)
|
||||||
|
else:
|
||||||
|
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, sheet_uri)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_drawing_to_sheet"
|
bl_idname = "bim.add_drawing_to_sheet"
|
||||||
bl_label = "Add Drawing To Sheet"
|
bl_label = "Add Selected Drawing To Sheet"
|
||||||
|
bl_description = "Add the drawing selected in the\nDrawings list below to the sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -1496,7 +1657,14 @@ class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
attributes = tool.Drawing.generate_reference_attributes(
|
attributes = tool.Drawing.generate_reference_attributes(
|
||||||
reference,
|
reference,
|
||||||
Identification=str(
|
Identification=str(
|
||||||
len([r for r in references if tool.Drawing.get_reference_description(r) in ("DRAWING", "SCHEDULE")]) + 1
|
len(
|
||||||
|
[
|
||||||
|
r
|
||||||
|
for r in references
|
||||||
|
if tool.Drawing.get_reference_description(r) in ("DRAWING", "SCHEDULE", "REFERENCE")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ 1
|
||||||
),
|
),
|
||||||
Location=drawing_reference.Location,
|
Location=drawing_reference.Location,
|
||||||
Description="DRAWING",
|
Description="DRAWING",
|
||||||
@@ -1512,9 +1680,20 @@ class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class RemoveDrawingFromSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class RemoveDrawingFromSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.remove_drawing_from_sheet"
|
bl_idname = "bim.remove_drawing_from_sheet"
|
||||||
bl_label = "Remove Drawing From Sheet"
|
bl_label = "Remove Drawing From Sheet"
|
||||||
|
bl_description = "Remove currently selected drawing from sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
reference: bpy.props.IntProperty()
|
reference: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
active_sheet = props.sheets[props.active_sheet_index]
|
||||||
|
|
||||||
|
if active_sheet.reference_type == "TITLEBLOCK":
|
||||||
|
cls.poll_message_set("No effect deleting this.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
reference = tool.Ifc.get().by_id(self.reference)
|
reference = tool.Ifc.get().by_id(self.reference)
|
||||||
sheet = tool.Drawing.get_reference_document(reference)
|
sheet = tool.Drawing.get_reference_document(reference)
|
||||||
@@ -1531,98 +1710,129 @@ class RemoveDrawingFromSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
|
class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.create_sheets"
|
bl_idname = "bim.create_sheets"
|
||||||
bl_label = "Create Sheets"
|
bl_label = "Create Sheets"
|
||||||
bl_description = "Build a sheet from the sheet layout"
|
bl_description = (
|
||||||
|
"Build and open selected sheet from the sheet layout and\n"
|
||||||
|
+ "optionally create .pdf and .dxf from commands in\n"
|
||||||
|
+ "the Bonsai preferences (if provided).\n\n"
|
||||||
|
+ "SHIFT+CLICK to create all shown checked sheets, but doesn't\n"
|
||||||
|
+ "open them for viewing\n\n"
|
||||||
|
+ "Add the CTRL modifier to optionally open sheets to view them as\n"
|
||||||
|
+ "they are created"
|
||||||
|
)
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
create_all: bpy.props.BoolProperty(name="Create All", default=False, options={"SKIP_SAVE"})
|
||||||
|
open_viewer: bpy.props.BoolProperty(name="Open in Viewer", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.scene.DocProperties.sheets and context.scene.BIMProperties.data_dir
|
props = context.scene.DocProperties
|
||||||
|
active_sheet = props.sheets[props.active_sheet_index]
|
||||||
|
if not active_sheet.is_sheet:
|
||||||
|
cls.poll_message_set("No sheet selected.")
|
||||||
|
return False
|
||||||
|
return props.sheets and context.scene.BIMProperties.data_dir
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
# opening all sheets on shift+click
|
||||||
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
|
if event.type == "LEFTMOUSE" and event.shift:
|
||||||
|
self.create_all = True
|
||||||
|
if event.type == "LEFTMOUSE" and event.ctrl:
|
||||||
|
self.open_viewer = True
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
props = scene.DocProperties
|
props = scene.DocProperties
|
||||||
active_sheet = props.sheets[props.active_sheet_index]
|
|
||||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
|
||||||
|
|
||||||
# Update any drawing boundary changes
|
|
||||||
sheet_builder = sheeter.SheetBuilder()
|
|
||||||
sheet_builder.update_sheet_drawing_sizes(sheet)
|
|
||||||
|
|
||||||
if not sheet.is_a("IfcDocumentInformation"):
|
|
||||||
return
|
|
||||||
|
|
||||||
name = os.path.splitext(os.path.basename(tool.Drawing.get_document_uri(sheet)))[0]
|
|
||||||
sheet_builder = sheeter.SheetBuilder()
|
|
||||||
sheet_builder.data_dir = scene.BIMProperties.data_dir
|
|
||||||
|
|
||||||
references = sheet_builder.build(sheet)
|
|
||||||
raster_references = [tool.Ifc.get_relative_uri(r) for r in references["RASTER"]]
|
|
||||||
|
|
||||||
# These variables will be made available to the evaluated commands
|
|
||||||
svg = references["SHEET"]
|
|
||||||
pdf = os.path.splitext(svg)[0] + ".pdf"
|
|
||||||
replacements = {
|
|
||||||
"svg": svg,
|
|
||||||
"basename": os.path.basename(svg),
|
|
||||||
"path": os.path.dirname(svg),
|
|
||||||
"pdf": pdf,
|
|
||||||
"eps": os.path.splitext(svg)[0] + ".eps",
|
|
||||||
"dxf": os.path.splitext(svg)[0] + ".dxf",
|
|
||||||
}
|
|
||||||
|
|
||||||
has_sheet_reference = False
|
|
||||||
for reference in tool.Drawing.get_document_references(sheet):
|
|
||||||
reference_description = tool.Drawing.get_reference_description(reference)
|
|
||||||
if reference_description == "SHEET":
|
|
||||||
has_sheet_reference = True
|
|
||||||
elif reference_description == "RASTER":
|
|
||||||
if reference.Location in raster_references:
|
|
||||||
raster_references.remove(reference.Location)
|
|
||||||
else:
|
|
||||||
tool.Ifc.run("document.remove_reference", reference=reference)
|
|
||||||
|
|
||||||
if not has_sheet_reference:
|
|
||||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
|
||||||
tool.Ifc.run(
|
|
||||||
"document.edit_reference",
|
|
||||||
reference=reference,
|
|
||||||
attributes=tool.Drawing.generate_reference_attributes(
|
|
||||||
reference, Location=tool.Ifc.get_relative_uri(svg), Description="SHEET"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
for raster_reference in raster_references:
|
|
||||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
|
||||||
tool.Ifc.run(
|
|
||||||
"document.edit_reference",
|
|
||||||
reference=reference,
|
|
||||||
attributes=tool.Drawing.generate_reference_attributes(
|
|
||||||
reference, Location=tool.Ifc.get_relative_uri(raster_reference), Description="RASTER"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
svg2pdf_command = tool.Blender.get_addon_preferences().svg2pdf_command
|
svg2pdf_command = tool.Blender.get_addon_preferences().svg2pdf_command
|
||||||
svg2dxf_command = tool.Blender.get_addon_preferences().svg2dxf_command
|
svg2dxf_command = tool.Blender.get_addon_preferences().svg2dxf_command
|
||||||
|
|
||||||
if svg2pdf_command:
|
if self.create_all:
|
||||||
# With great power comes great responsibility. Example:
|
sheets = [tool.Ifc.get().by_id(s.ifc_definition_id) for s in props.sheets if s.is_sheet and s.is_selected]
|
||||||
# [["inkscape", "svg", "-o", "pdf"]]
|
|
||||||
commands = json.loads(svg2pdf_command)
|
|
||||||
for command in commands:
|
|
||||||
subprocess.run([replacements.get(c, c) for c in command])
|
|
||||||
|
|
||||||
if svg2dxf_command:
|
|
||||||
# With great power comes great responsibility. Example:
|
|
||||||
# [["inkscape", "svg", "-o", "eps"], ["pstoedit", "-dt", "-f", "dxf:-polyaslines -mm", "eps", "dxf", "-psarg", "-dNOSAFER"]]
|
|
||||||
commands = json.loads(svg2dxf_command)
|
|
||||||
for command in commands:
|
|
||||||
command[0] = shutil.which(command[0]) or command[0]
|
|
||||||
subprocess.run([replacements.get(c, c) for c in command])
|
|
||||||
|
|
||||||
if svg2pdf_command:
|
|
||||||
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, pdf)
|
|
||||||
else:
|
else:
|
||||||
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg)
|
sheets = [tool.Ifc.get().by_id(props.sheets[props.active_sheet_index].ifc_definition_id)]
|
||||||
|
|
||||||
|
for sheet in sheets:
|
||||||
|
# Update any drawing boundary changes
|
||||||
|
sheet_builder = sheeter.SheetBuilder()
|
||||||
|
sheet_builder.update_sheet_drawing_sizes(sheet)
|
||||||
|
|
||||||
|
if not sheet.is_a("IfcDocumentInformation"):
|
||||||
|
return
|
||||||
|
|
||||||
|
name = os.path.splitext(os.path.basename(tool.Drawing.get_document_uri(sheet)))[0]
|
||||||
|
sheet_builder = sheeter.SheetBuilder()
|
||||||
|
sheet_builder.data_dir = scene.BIMProperties.data_dir
|
||||||
|
|
||||||
|
references = sheet_builder.build(sheet)
|
||||||
|
raster_references = [tool.Ifc.get_relative_uri(r) for r in references["RASTER"]]
|
||||||
|
|
||||||
|
# These variables will be made available to the evaluated commands
|
||||||
|
svg = references["SHEET"]
|
||||||
|
pdf = os.path.splitext(svg)[0] + ".pdf"
|
||||||
|
replacements = {
|
||||||
|
"svg": svg,
|
||||||
|
"basename": os.path.basename(svg),
|
||||||
|
"path": os.path.dirname(svg),
|
||||||
|
"pdf": pdf,
|
||||||
|
"eps": os.path.splitext(svg)[0] + ".eps",
|
||||||
|
"dxf": os.path.splitext(svg)[0] + ".dxf",
|
||||||
|
}
|
||||||
|
|
||||||
|
has_sheet_reference = False
|
||||||
|
for reference in tool.Drawing.get_document_references(sheet):
|
||||||
|
reference_description = tool.Drawing.get_reference_description(reference)
|
||||||
|
if reference_description == "SHEET":
|
||||||
|
has_sheet_reference = True
|
||||||
|
elif reference_description == "RASTER":
|
||||||
|
if reference.Location in raster_references:
|
||||||
|
raster_references.remove(reference.Location)
|
||||||
|
else:
|
||||||
|
tool.Ifc.run("document.remove_reference", reference=reference)
|
||||||
|
|
||||||
|
if not has_sheet_reference:
|
||||||
|
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||||
|
tool.Ifc.run(
|
||||||
|
"document.edit_reference",
|
||||||
|
reference=reference,
|
||||||
|
attributes=tool.Drawing.generate_reference_attributes(
|
||||||
|
reference, Location=tool.Ifc.get_relative_uri(svg), Description="SHEET"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
for raster_reference in raster_references:
|
||||||
|
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||||
|
tool.Ifc.run(
|
||||||
|
"document.edit_reference",
|
||||||
|
reference=reference,
|
||||||
|
attributes=tool.Drawing.generate_reference_attributes(
|
||||||
|
reference, Location=tool.Ifc.get_relative_uri(raster_reference), Description="RASTER"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if svg2pdf_command:
|
||||||
|
# With great power comes great responsibility. Example:
|
||||||
|
# [["inkscape", "svg", "-o", "pdf"]]
|
||||||
|
commands = json.loads(svg2pdf_command)
|
||||||
|
for command in commands:
|
||||||
|
subprocess.run([replacements.get(c, c) for c in command])
|
||||||
|
|
||||||
|
if svg2dxf_command:
|
||||||
|
# With great power comes great responsibility. Example:
|
||||||
|
# [["inkscape", "svg", "-o", "eps"], ["pstoedit", "-dt", "-f", "dxf:-polyaslines -mm", "eps", "dxf", "-psarg", "-dNOSAFER"]]
|
||||||
|
commands = json.loads(svg2dxf_command)
|
||||||
|
for command in commands:
|
||||||
|
command[0] = shutil.which(command[0]) or command[0]
|
||||||
|
subprocess.run([replacements.get(c, c) for c in command])
|
||||||
|
|
||||||
|
if self.open_viewer:
|
||||||
|
if svg2pdf_command:
|
||||||
|
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, pdf)
|
||||||
|
else:
|
||||||
|
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg)
|
||||||
|
if not self.open_viewer:
|
||||||
|
self.report({"INFO"}, f"{len(sheets)} sheets created...")
|
||||||
|
|
||||||
|
|
||||||
class SelectAllDrawings(bpy.types.Operator):
|
class SelectAllDrawings(bpy.types.Operator):
|
||||||
@@ -1651,12 +1861,20 @@ class OpenDrawing(bpy.types.Operator):
|
|||||||
bl_label = "Open Drawing"
|
bl_label = "Open Drawing"
|
||||||
view: bpy.props.StringProperty()
|
view: bpy.props.StringProperty()
|
||||||
bl_description = (
|
bl_description = (
|
||||||
"Opens a .svg drawing based on currently active camera with default system viewer\n"
|
"Opens selected .svg drawing with default system viewer\n"
|
||||||
+ 'or using "svg_command" from the Bonsai preferences (if provided).\n\n'
|
+ 'or using "svg_command" from the Bonsai preferences (if provided).\n\n'
|
||||||
+ "SHIFT+CLICK to open all selected drawings"
|
+ "SHIFT+CLICK to open all shown checked drawings"
|
||||||
)
|
)
|
||||||
open_all: bpy.props.BoolProperty(name="Open All", default=False, options={"SKIP_SAVE"})
|
open_all: bpy.props.BoolProperty(name="Open All", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
# opening all drawings on shift+click
|
# opening all drawings on shift+click
|
||||||
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
@@ -1665,12 +1883,13 @@ class OpenDrawing(bpy.types.Operator):
|
|||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
self.props = context.scene.DocProperties
|
||||||
if self.open_all:
|
if self.open_all:
|
||||||
drawings = [
|
drawings = [
|
||||||
tool.Ifc.get().by_id(d.ifc_definition_id) for d in context.scene.DocProperties.drawings if d.is_selected
|
tool.Ifc.get().by_id(d.ifc_definition_id) for d in self.props.drawings if d.is_drawing and d.is_selected
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
drawings = [tool.Ifc.get().by_id(context.scene.DocProperties.drawings.get(self.view).ifc_definition_id)]
|
drawings = [tool.Ifc.get().by_id(self.props.drawings.get(self.view).ifc_definition_id)]
|
||||||
|
|
||||||
drawing_uris = []
|
drawing_uris = []
|
||||||
drawings_not_found = []
|
drawings_not_found = []
|
||||||
@@ -1682,7 +1901,7 @@ class OpenDrawing(bpy.types.Operator):
|
|||||||
drawings_not_found.append(drawing.Name)
|
drawings_not_found.append(drawing.Name)
|
||||||
|
|
||||||
if drawings_not_found:
|
if drawings_not_found:
|
||||||
msg = "Some drawings .svg files were not found, need to print them first: \n{}.".format(
|
msg = "Some drawings .svg files were not found, need to create them first: \n{}.".format(
|
||||||
"\n".join(drawings_not_found)
|
"\n".join(drawings_not_found)
|
||||||
)
|
)
|
||||||
self.report({"ERROR"}, msg)
|
self.report({"ERROR"}, msg)
|
||||||
@@ -1755,20 +1974,7 @@ class ActivateModel(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ActivateDrawing(bpy.types.Operator):
|
class ActivateDrawingBase:
|
||||||
bl_idname = "bim.activate_drawing"
|
|
||||||
bl_label = "Activate Drawing"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
bl_description = (
|
|
||||||
"Activates the selected drawing view.\n\n"
|
|
||||||
+ "ALT+CLICK to keep the viewport position.\n\n"
|
|
||||||
+ "SHIFT+CLICK to load a quick preview of the drawing view."
|
|
||||||
)
|
|
||||||
|
|
||||||
drawing: bpy.props.IntProperty()
|
|
||||||
should_view_from_camera: bpy.props.BoolProperty(name="Should View From Camera", default=True, options={"SKIP_SAVE"})
|
|
||||||
use_quick_preview: bpy.props.BoolProperty(name="Use Quick Preview", default=False, options={"SKIP_SAVE"})
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
if event.type == "LEFTMOUSE" and event.alt:
|
if event.type == "LEFTMOUSE" and event.alt:
|
||||||
self.should_view_from_camera = False
|
self.should_view_from_camera = False
|
||||||
@@ -1817,6 +2023,54 @@ class ActivateDrawing(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ActivateDrawing(bpy.types.Operator, ActivateDrawingBase):
|
||||||
|
bl_idname = "bim.activate_drawing"
|
||||||
|
bl_label = "Activate Drawing"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
bl_description = (
|
||||||
|
"Activates the selected drawing view.\n\n"
|
||||||
|
+ "ALT+CLICK to keep the viewport position.\n\n"
|
||||||
|
+ "SHIFT+CLICK to load a quick preview of the drawing view"
|
||||||
|
)
|
||||||
|
|
||||||
|
drawing: bpy.props.IntProperty()
|
||||||
|
should_view_from_camera: bpy.props.BoolProperty(name="Should View From Camera", default=True, options={"SKIP_SAVE"})
|
||||||
|
use_quick_preview: bpy.props.BoolProperty(name="Use Quick Preview", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ActivateDrawingFromSheet(bpy.types.Operator, ActivateDrawingBase):
|
||||||
|
bl_idname = "bim.activate_drawing_from_sheet"
|
||||||
|
bl_label = "Activate Drawing"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
bl_description = (
|
||||||
|
"Activates the selected drawing view.\n\n"
|
||||||
|
+ "ALT+CLICK to keep the viewport position.\n\n"
|
||||||
|
+ "SHIFT+CLICK to load a quick preview of the drawing view"
|
||||||
|
)
|
||||||
|
|
||||||
|
drawing: bpy.props.IntProperty()
|
||||||
|
should_view_from_camera: bpy.props.BoolProperty(name="Should View From Camera", default=True, options={"SKIP_SAVE"})
|
||||||
|
use_quick_preview: bpy.props.BoolProperty(name="Use Quick Preview", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
active_sheet = props.sheets[props.active_sheet_index]
|
||||||
|
is_drawing_selected = active_sheet.reference_type == "DRAWING"
|
||||||
|
if not is_drawing_selected:
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class SelectDocIfcFile(bpy.types.Operator):
|
class SelectDocIfcFile(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_doc_ifc_file"
|
bl_idname = "bim.select_doc_ifc_file"
|
||||||
bl_label = "Select Documentation IFC File"
|
bl_label = "Select Documentation IFC File"
|
||||||
@@ -1856,6 +2110,14 @@ class RemoveDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
drawing: bpy.props.IntProperty()
|
drawing: bpy.props.IntProperty()
|
||||||
remove_all: bpy.props.BoolProperty(name="Remove All", default=False, options={"SKIP_SAVE"})
|
remove_all: bpy.props.BoolProperty(name="Remove All", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
# removing all selected drawings on shift+click
|
# removing all selected drawings on shift+click
|
||||||
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
@@ -1866,7 +2128,9 @@ class RemoveDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
if self.remove_all:
|
if self.remove_all:
|
||||||
drawings = [
|
drawings = [
|
||||||
tool.Ifc.get().by_id(d.ifc_definition_id) for d in context.scene.DocProperties.drawings if d.is_selected
|
tool.Ifc.get().by_id(d.ifc_definition_id)
|
||||||
|
for d in context.scene.DocProperties.drawings
|
||||||
|
if d.is_drawing and d.is_selected
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
if not self.drawing:
|
if not self.drawing:
|
||||||
@@ -2192,6 +2456,7 @@ class RemoveSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_idname = "bim.remove_sheet"
|
bl_idname = "bim.remove_sheet"
|
||||||
bl_label = "Remove Sheet"
|
bl_label = "Remove Sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
bl_description = "Remove currently selected sheet"
|
||||||
sheet: bpy.props.IntProperty()
|
sheet: bpy.props.IntProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
@@ -2260,11 +2525,15 @@ class BuildSchedule(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_schedule_to_sheet"
|
bl_idname = "bim.add_schedule_to_sheet"
|
||||||
bl_label = "Add Schedule To Sheet"
|
bl_label = "Add Schedule To Sheet"
|
||||||
|
bl_description = "Add the schedule selected in the\nSchedules list below to the sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
props = context.scene.DocProperties
|
props = context.scene.DocProperties
|
||||||
|
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
|
return props.schedules and props.sheets and context.scene.BIMProperties.data_dir
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
@@ -2299,7 +2568,14 @@ class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
attributes = tool.Drawing.generate_reference_attributes(
|
attributes = tool.Drawing.generate_reference_attributes(
|
||||||
reference,
|
reference,
|
||||||
Identification=str(
|
Identification=str(
|
||||||
len([r for r in references if tool.Drawing.get_reference_description(r) in ("DRAWING", "SCHEDULE")]) + 1
|
len(
|
||||||
|
[
|
||||||
|
r
|
||||||
|
for r in references
|
||||||
|
if tool.Drawing.get_reference_description(r) in ("DRAWING", "SCHEDULE", "REFERENCE")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ 1
|
||||||
),
|
),
|
||||||
Location=schedule_location,
|
Location=schedule_location,
|
||||||
Description="SCHEDULE",
|
Description="SCHEDULE",
|
||||||
@@ -2316,11 +2592,15 @@ class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_reference_to_sheet"
|
bl_idname = "bim.add_reference_to_sheet"
|
||||||
bl_label = "Add Reference To Sheet"
|
bl_label = "Add Reference To Sheet"
|
||||||
|
bl_description = "Add the reference selected in the\nReferences list below to the sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
props = context.scene.DocProperties
|
props = context.scene.DocProperties
|
||||||
|
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
|
return props.references and props.sheets and context.scene.BIMProperties.data_dir
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
@@ -2355,7 +2635,13 @@ class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
attributes = tool.Drawing.generate_reference_attributes(
|
attributes = tool.Drawing.generate_reference_attributes(
|
||||||
reference,
|
reference,
|
||||||
Identification=str(
|
Identification=str(
|
||||||
len([r for r in references if tool.Drawing.get_reference_description(r) in ("DRAWING", "REFERENCE")])
|
len(
|
||||||
|
[
|
||||||
|
r
|
||||||
|
for r in references
|
||||||
|
if tool.Drawing.get_reference_description(r) in ("DRAWING", "SCHEDULE", "REFERENCE")
|
||||||
|
]
|
||||||
|
)
|
||||||
+ 1
|
+ 1
|
||||||
),
|
),
|
||||||
Location=extref_location,
|
Location=extref_location,
|
||||||
@@ -2720,7 +3006,8 @@ class LoadSheets(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.edit_sheet"
|
bl_idname = "bim.edit_sheet"
|
||||||
bl_label = "Edit Sheet"
|
bl_label = "Edit Sheet / Drawing"
|
||||||
|
bl_description = "Edit details of sheet or drawing"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
identification: bpy.props.StringProperty()
|
identification: bpy.props.StringProperty()
|
||||||
name: bpy.props.StringProperty()
|
name: bpy.props.StringProperty()
|
||||||
@@ -3069,20 +3356,30 @@ class ConvertSVGToDXF(bpy.types.Operator):
|
|||||||
bl_label = "Convert SVG to DXF"
|
bl_label = "Convert SVG to DXF"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
view: bpy.props.StringProperty()
|
view: bpy.props.StringProperty()
|
||||||
bl_description = "Convert current drawing's .svg to .dxf.\n\nSHIFT+CLICK to convert all selected drawings"
|
bl_description = "Convert selected drawing's .svg to .dxf.\n\nSHIFT+CLICK to convert all shown checked drawings"
|
||||||
convert_all: bpy.props.BoolProperty(name="Convert All", default=False, options={"SKIP_SAVE"})
|
convert_all: bpy.props.BoolProperty(name="Convert All", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
props = context.scene.DocProperties
|
||||||
|
if not tool.Drawing.get_active_drawing_item():
|
||||||
|
cls.poll_message_set("No drawing selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
# convert all drawings on shift+click
|
# convert all drawings on shift+click
|
||||||
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
if event.type == "LEFTMOUSE" and event.shift:
|
if event.type == "LEFTMOUSE" and event.shift:
|
||||||
self.open_all = True
|
self.convert_all = True
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if self.convert_all:
|
if self.convert_all:
|
||||||
drawings = [
|
drawings = [
|
||||||
tool.Ifc.get().by_id(d.ifc_definition_id) for d in context.scene.DocProperties.drawings if d.is_selected
|
tool.Ifc.get().by_id(d.ifc_definition_id)
|
||||||
|
for d in context.scene.DocProperties.drawings
|
||||||
|
if d.is_drawing and d.is_selected
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
drawings = [tool.Ifc.get().by_id(context.scene.DocProperties.drawings.get(self.view).ifc_definition_id)]
|
drawings = [tool.Ifc.get().by_id(context.scene.DocProperties.drawings.get(self.view).ifc_definition_id)]
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ class Sheet(PropertyGroup):
|
|||||||
identification: StringProperty(name="Identification")
|
identification: StringProperty(name="Identification")
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
is_sheet: BoolProperty(name="Is Sheet", default=False)
|
is_sheet: BoolProperty(name="Is Sheet", default=False)
|
||||||
|
is_selected: BoolProperty(name="Is Selected", default=True)
|
||||||
reference_type: StringProperty(name="Reference Type")
|
reference_type: StringProperty(name="Reference Type")
|
||||||
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
||||||
|
|
||||||
|
|||||||
@@ -92,11 +92,6 @@ class BIM_PT_camera(Panel):
|
|||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.prop(props, "dpi")
|
row.prop(props, "dpi")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.operator("bim.create_drawing", text="Create Drawing", icon="OUTPUT")
|
|
||||||
op = row.operator("bim.open_drawing", icon="URL", text="")
|
|
||||||
op.view = context.scene.camera.name.split("/")[1]
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_element_filters(Panel):
|
class BIM_PT_element_filters(Panel):
|
||||||
bl_label = "Element Filters"
|
bl_label = "Element Filters"
|
||||||
@@ -252,43 +247,29 @@ class BIM_PT_drawings(Panel):
|
|||||||
if self.props.active_drawing_index < len(self.props.drawings):
|
if self.props.active_drawing_index < len(self.props.drawings):
|
||||||
active_drawing = self.props.drawings[self.props.active_drawing_index]
|
active_drawing = self.props.drawings[self.props.active_drawing_index]
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
col = row.column()
|
row2 = row.row(align=True)
|
||||||
col.alignment = "LEFT"
|
|
||||||
row2 = col.row(align=True)
|
|
||||||
row2.operator("bim.remove_drawing", icon="X", text="").drawing = active_drawing.ifc_definition_id
|
row2.operator("bim.remove_drawing", icon="X", text="").drawing = active_drawing.ifc_definition_id
|
||||||
|
|
||||||
row2.operator("bim.duplicate_drawing", icon="COPYDOWN", text="").drawing = (
|
row2.separator(factor=0.5, type="SPACE")
|
||||||
|
|
||||||
|
row2.operator("bim.duplicate_drawing", icon="DUPLICATE", text="").drawing = (
|
||||||
active_drawing.ifc_definition_id
|
active_drawing.ifc_definition_id
|
||||||
)
|
)
|
||||||
|
|
||||||
col = row.column()
|
row3 = row.row(align=True)
|
||||||
col.alignment = "RIGHT"
|
row3.alignment = "RIGHT"
|
||||||
|
|
||||||
convert_to_dxf = row.row(align=True)
|
row3.operator("bim.activate_drawing", icon="OUTLINER_OB_CAMERA", text="").drawing = (
|
||||||
op = convert_to_dxf.operator("bim.convert_svg_to_dxf", text="", icon="IMAGE_DATA")
|
active_drawing.ifc_definition_id
|
||||||
op.view = active_drawing.name
|
)
|
||||||
convert_to_dxf.enabled = active_drawing.ifc_definition_id > 0
|
row3.operator("bim.activate_model", icon="VIEW3D", text="")
|
||||||
|
|
||||||
op = row.operator("bim.select_all_drawings", icon="SELECT_SUBTRACT", text="")
|
row3.separator(factor=0.5, type="SPACE")
|
||||||
|
|
||||||
open_drawing_button = row.row(align=True)
|
row3.operator("bim.select_all_drawings", icon="CHECKBOX_HLT", text="")
|
||||||
op = open_drawing_button.operator("bim.open_drawing", icon="URL", text="")
|
row3.operator("bim.create_drawing", text="", icon="OUTPUT")
|
||||||
op.view = active_drawing.name
|
row3.operator("bim.convert_svg_to_dxf", text="", icon="SEQ_PREVIEW").view = active_drawing.name
|
||||||
open_drawing_button.enabled = active_drawing.ifc_definition_id > 0
|
row3.operator("bim.open_drawing", icon="HIDE_OFF", text="").view = active_drawing.name
|
||||||
|
|
||||||
row.operator("bim.activate_model", icon="VIEW3D", text="")
|
|
||||||
|
|
||||||
drawing_button = row.row(align=True)
|
|
||||||
op = drawing_button.operator("bim.activate_drawing", icon="OUTLINER_OB_CAMERA", text="")
|
|
||||||
op.drawing = active_drawing.ifc_definition_id
|
|
||||||
drawing_button.enabled = active_drawing.ifc_definition_id > 0
|
|
||||||
|
|
||||||
create_drawing_button = row.row(align=True)
|
|
||||||
create_drawing_button.operator("bim.create_drawing", text="", icon="OUTPUT")
|
|
||||||
create_drawing_button.enabled = active_drawing.ifc_definition_id > 0
|
|
||||||
|
|
||||||
# might need a different icon since the URL icon is already used by the open_drawing
|
|
||||||
row.operator("bim.open_documentation_web_ui", icon="URL", text="")
|
|
||||||
self.layout.template_list(
|
self.layout.template_list(
|
||||||
"BIM_UL_drawinglist", "", self.props, "drawings", self.props, "active_drawing_index"
|
"BIM_UL_drawinglist", "", self.props, "drawings", self.props, "active_drawing_index"
|
||||||
)
|
)
|
||||||
@@ -325,7 +306,7 @@ class BIM_PT_schedules(Panel):
|
|||||||
|
|
||||||
if not self.props.is_editing_schedules:
|
if not self.props.is_editing_schedules:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=f"{DocumentsData.data['total_schedules']} Schedules Found", icon="LONGDISPLAY")
|
row.label(text=f"{DocumentsData.data['total_schedules']} Schedules Found", icon="PRESET")
|
||||||
row.operator("bim.load_schedules", text="", icon="IMPORT")
|
row.operator("bim.load_schedules", text="", icon="IMPORT")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -375,7 +356,7 @@ class BIM_PT_references(Panel):
|
|||||||
|
|
||||||
if not self.props.is_editing_references:
|
if not self.props.is_editing_references:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=f"{DocumentsData.data['total_references']} References Found", icon="OBJECT_HIDDEN")
|
row.label(text=f"{DocumentsData.data['total_references']} References Found", icon="IMAGE_REFERENCE")
|
||||||
row.operator("bim.load_references", text="", icon="IMPORT")
|
row.operator("bim.load_references", text="", icon="IMPORT")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -429,7 +410,23 @@ class BIM_PT_sheets(Panel):
|
|||||||
if self.props.sheets and self.props.active_sheet_index < len(self.props.sheets):
|
if self.props.sheets and self.props.active_sheet_index < len(self.props.sheets):
|
||||||
active_sheet = self.props.sheets[self.props.active_sheet_index]
|
active_sheet = self.props.sheets[self.props.active_sheet_index]
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.alignment = "RIGHT"
|
row2 = row.row(align=True)
|
||||||
|
if active_sheet.is_sheet:
|
||||||
|
row2.operator("bim.remove_sheet", icon="X", text="").sheet = active_sheet.ifc_definition_id
|
||||||
|
else:
|
||||||
|
row2.operator("bim.remove_drawing_from_sheet", icon="X", text="").reference = (
|
||||||
|
active_sheet.ifc_definition_id
|
||||||
|
)
|
||||||
|
|
||||||
|
row2.separator(factor=0.5, type="SPACE")
|
||||||
|
|
||||||
|
row2.operator("bim.duplicate_sheet", icon="DUPLICATE", text="").drawing = active_sheet.ifc_definition_id
|
||||||
|
row2.operator("bim.open_documentation_web_ui", icon="URL", text="")
|
||||||
|
|
||||||
|
row3 = row.row(align=True)
|
||||||
|
row3.alignment = "RIGHT"
|
||||||
|
|
||||||
|
op = row3.operator("bim.activate_drawing_from_sheet", icon="OUTLINER_OB_CAMERA", text="")
|
||||||
|
|
||||||
if active_sheet.reference_type == "DRAWING":
|
if active_sheet.reference_type == "DRAWING":
|
||||||
drawingnamesvg = active_sheet.name
|
drawingnamesvg = active_sheet.name
|
||||||
@@ -445,23 +442,21 @@ class BIM_PT_sheets(Panel):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if drawingid is not None:
|
if drawingid is not None:
|
||||||
drawing_button = row.row(align=True)
|
|
||||||
op = drawing_button.operator("bim.activate_drawing", icon="OUTLINER_OB_CAMERA", text="")
|
|
||||||
op.drawing = drawingid
|
op.drawing = drawingid
|
||||||
else:
|
|
||||||
print(f"No matching drawing ID found for {drawingname}")
|
|
||||||
|
|
||||||
row.operator("bim.edit_sheet", icon="GREASEPENCIL", text="")
|
row3.separator(factor=0.5, type="SPACE")
|
||||||
row.operator("bim.open_sheet", icon="URL", text="")
|
|
||||||
row.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
row3.operator("bim.edit_sheet", icon="GREASEPENCIL", text="")
|
||||||
row.operator("bim.add_schedule_to_sheet", icon="PRESET_NEW", text="")
|
row3.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
||||||
row.operator("bim.add_reference_to_sheet", icon="IMAGE_REFERENCE", text="")
|
row3.operator("bim.add_schedule_to_sheet", icon="PRESET_NEW", text="")
|
||||||
row.operator("bim.create_sheets", icon="FILE_REFRESH", text="")
|
row3.operator("bim.add_reference_to_sheet", icon="IMAGE_REFERENCE", text="")
|
||||||
if active_sheet.is_sheet:
|
row3.operator("bim.open_layout", icon="CURRENT_FILE", text="")
|
||||||
row.operator("bim.remove_sheet", icon="X", text="").sheet = active_sheet.ifc_definition_id
|
|
||||||
else:
|
row3.separator(factor=0.5, type="SPACE")
|
||||||
op = row.operator("bim.remove_drawing_from_sheet", icon="X", text="")
|
|
||||||
op.reference = active_sheet.ifc_definition_id
|
row3.operator("bim.select_all_sheets", icon="CHECKBOX_HLT", text="")
|
||||||
|
row3.operator("bim.create_sheets", icon="OUTPUT", text="")
|
||||||
|
row3.operator("bim.open_sheet", icon="HIDE_OFF", text="")
|
||||||
|
|
||||||
self.layout.template_list("BIM_UL_sheets", "", self.props, "sheets", self.props, "active_sheet_index")
|
self.layout.template_list("BIM_UL_sheets", "", self.props, "sheets", self.props, "active_sheet_index")
|
||||||
|
|
||||||
@@ -600,6 +595,13 @@ class BIM_UL_drawinglist(bpy.types.UIList):
|
|||||||
selected_icon = "CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
|
selected_icon = "CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
|
||||||
row.prop(item, "is_selected", text="", icon=selected_icon, emboss=False)
|
row.prop(item, "is_selected", text="", icon=selected_icon, emboss=False)
|
||||||
row.prop(item, "name", text="", emboss=False)
|
row.prop(item, "name", text="", emboss=False)
|
||||||
|
self.props = context.scene.DocProperties
|
||||||
|
if (
|
||||||
|
self.props.drawings
|
||||||
|
and self.props.active_drawing_id
|
||||||
|
and item.ifc_definition_id == self.props.active_drawing_id
|
||||||
|
):
|
||||||
|
row.label(text="", icon="OUTLINER_OB_CAMERA")
|
||||||
else:
|
else:
|
||||||
if item.target_view == "PLAN_VIEW":
|
if item.target_view == "PLAN_VIEW":
|
||||||
icon = "UV_FACESEL"
|
icon = "UV_FACESEL"
|
||||||
@@ -641,13 +643,16 @@ class BIM_UL_sheets(bpy.types.UIList):
|
|||||||
item.ifc_definition_id
|
item.ifc_definition_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
selected_icon = "CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
|
||||||
|
row.prop(item, "is_selected", text="", icon=selected_icon, emboss=False)
|
||||||
|
|
||||||
row.label(text=f"{item.identification} - {item.name}")
|
row.label(text=f"{item.identification} - {item.name}")
|
||||||
else:
|
else:
|
||||||
row.label(text="", icon="BLANK1")
|
row.label(text="", icon="BLANK1")
|
||||||
if item.reference_type == "DRAWING":
|
if item.reference_type == "DRAWING":
|
||||||
row.label(text="", icon="IMAGE_DATA")
|
row.label(text="", icon="IMAGE_DATA")
|
||||||
elif item.reference_type == "SCHEDULE":
|
elif item.reference_type == "SCHEDULE":
|
||||||
row.label(text="", icon="LONGDISPLAY")
|
row.label(text="", icon="PRESET")
|
||||||
elif item.reference_type == "TITLEBLOCK":
|
elif item.reference_type == "TITLEBLOCK":
|
||||||
row.label(text="", icon="MENU_PANEL")
|
row.label(text="", icon="MENU_PANEL")
|
||||||
elif item.reference_type == "REVISION":
|
elif item.reference_type == "REVISION":
|
||||||
|
|||||||
@@ -745,7 +745,6 @@ class ExpandMaterialCategory(bpy.types.Operator):
|
|||||||
category.is_expanded = True
|
category.is_expanded = True
|
||||||
if category.name == self.category:
|
if category.name == self.category:
|
||||||
props.active_material_index = index
|
props.active_material_index = index
|
||||||
break
|
|
||||||
core.load_materials(tool.Material, props.material_type)
|
core.load_materials(tool.Material, props.material_type)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -775,7 +774,6 @@ class ContractMaterialCategory(bpy.types.Operator):
|
|||||||
category.is_expanded = False
|
category.is_expanded = False
|
||||||
if category.name == self.category:
|
if category.name == self.category:
|
||||||
props.active_material_index = index
|
props.active_material_index = index
|
||||||
break
|
|
||||||
core.load_materials(tool.Material, props.material_type)
|
core.load_materials(tool.Material, props.material_type)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -109,10 +109,16 @@ class BimTool(WorkSpaceTool):
|
|||||||
def draw_settings(cls, context, layout, ws_tool):
|
def draw_settings(cls, context, layout, ws_tool):
|
||||||
if context.scene.BIMGeometryProperties.mode == "ITEM":
|
if context.scene.BIMGeometryProperties.mode == "ITEM":
|
||||||
EditItemUI.draw(context, layout)
|
EditItemUI.draw(context, layout)
|
||||||
elif context.active_object and context.selected_objects and tool.Ifc.get_entity(context.active_object):
|
elif (
|
||||||
|
active_ifc_object := (context.active_object and tool.Ifc.get_entity(context.active_object))
|
||||||
|
) and context.selected_objects:
|
||||||
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
||||||
else:
|
else:
|
||||||
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
||||||
|
# Show some UI for spatial elements that are unselectable by default.
|
||||||
|
if active_ifc_object:
|
||||||
|
EditObjectUI.layout = layout # Prevent .draw_modes from using old layout and crash.
|
||||||
|
EditObjectUI.draw_modes(context)
|
||||||
|
|
||||||
|
|
||||||
class WallTool(BimTool):
|
class WallTool(BimTool):
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import bonsai.core.profile as core
|
|||||||
from bonsai.bim.module.model.decorator import ProfileDecorator
|
from bonsai.bim.module.model.decorator import ProfileDecorator
|
||||||
from bonsai.bim.module.profile.prop import generate_thumbnail_for_active_profile
|
from bonsai.bim.module.profile.prop import generate_thumbnail_for_active_profile
|
||||||
from bonsai.bim.module.profile.data import refresh
|
from bonsai.bim.module.profile.data import refresh
|
||||||
|
from bonsai.bim.module.geometry.helper import Helper
|
||||||
|
|
||||||
|
|
||||||
class LoadProfiles(bpy.types.Operator):
|
class LoadProfiles(bpy.types.Operator):
|
||||||
@@ -151,27 +152,36 @@ class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
obj_points = []
|
|
||||||
obj = context.scene.BIMProfileProperties.object_to_profile
|
|
||||||
if obj:
|
|
||||||
if len(obj.data.polygons) != 1:
|
|
||||||
self.report({"WARNING"}, "This mesh is invalid to create a profile. Select a flat mesh with no more then one face.")
|
|
||||||
return
|
|
||||||
for v in obj.data.polygons[0].vertices:
|
|
||||||
vert = obj.data.vertices[v]
|
|
||||||
if vert.co.z > 0:
|
|
||||||
self.report({"WARNING"}, "This mesh is invalid to create a profile. Select a flat mesh with all its vertices at z=0")
|
|
||||||
return
|
|
||||||
obj_points.append((vert.co.x, vert.co.y))
|
|
||||||
if obj_points:
|
|
||||||
obj_points.append(obj_points[0])
|
|
||||||
obj_points = [(v[0] - obj_points[0][0], v[1] - obj_points[0][1]) for v in obj_points] # Make sure the first point is (0, 0)
|
|
||||||
|
|
||||||
props = context.scene.BIMProfileProperties
|
props = context.scene.BIMProfileProperties
|
||||||
profile_class = props.profile_classes
|
profile_class = props.profile_classes
|
||||||
if profile_class == "IfcArbitraryClosedProfileDef":
|
if profile_class == "IfcArbitraryClosedProfileDef":
|
||||||
points = [(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)] if not obj_points else obj_points
|
obj = props.object_to_profile
|
||||||
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
if obj:
|
||||||
|
if len(obj.data.polygons) == 0:
|
||||||
|
self.report({"WARNING"}, "This mesh is invalid to create a profile. Select a flat mesh with at least one face.")
|
||||||
|
props.object_to_profile = None
|
||||||
|
return
|
||||||
|
helper = Helper(tool.Ifc.get())
|
||||||
|
indices = helper.auto_detect_arbitrary_profile_with_voids_extruded_area_solid(obj.data)
|
||||||
|
if not indices["inner_curves"]:
|
||||||
|
indices = helper.auto_detect_arbitrary_closed_profile_extruded_area_solid(obj.data)
|
||||||
|
props.object_to_profile = None
|
||||||
|
if not indices:
|
||||||
|
points = [(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]
|
||||||
|
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
||||||
|
else:
|
||||||
|
if "inner_curves" not in indices:
|
||||||
|
points = [(obj.data.vertices[i].co.x,obj.data.vertices[i].co.y) for i in indices["profile"]]
|
||||||
|
points.append(points[0])
|
||||||
|
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
||||||
|
else:
|
||||||
|
outer_points = [(obj.data.vertices[i].co.x,obj.data.vertices[i].co.y) for i in indices["profile"]]
|
||||||
|
outer_points.append(outer_points[0])
|
||||||
|
inner_points = [[(obj.data.vertices[i].co.x,obj.data.vertices[i].co.y) for i in curve] for curve in indices["inner_curves"]]
|
||||||
|
for curve in inner_points:
|
||||||
|
curve.append(curve[0])
|
||||||
|
profile = ifcopenshell.api.run("profile.add_arbitrary_profile_with_voids", tool.Ifc.get(), outer_profile=outer_points, inner_profiles=inner_points)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
profile = ifcopenshell.api.run("profile.add_parameterized_profile", tool.Ifc.get(), ifc_class=profile_class)
|
profile = ifcopenshell.api.run("profile.add_parameterized_profile", tool.Ifc.get(), ifc_class=profile_class)
|
||||||
tool.Profile.set_default_profile_attrs(profile)
|
tool.Profile.set_default_profile_attrs(profile)
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ class BIMProfileProperties(PropertyGroup):
|
|||||||
description="Check to only show IfcProfileDefs attached to IfcMaterialProfiles",
|
description="Check to only show IfcProfileDefs attached to IfcMaterialProfiles",
|
||||||
update=lambda self, context: bpy.ops.bim.load_profiles(),
|
update=lambda self, context: bpy.ops.bim.load_profiles(),
|
||||||
)
|
)
|
||||||
object_to_profile: PointerProperty(name="Object to profile", type=bpy.types.Object, description="Object to copy the mesh to a profile")
|
object_to_profile: PointerProperty(
|
||||||
|
name="Object to profile", type=bpy.types.Object, description="Object to copy the mesh to a profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_thumbnail_for_active_profile():
|
def generate_thumbnail_for_active_profile():
|
||||||
|
|||||||
@@ -2503,7 +2503,6 @@ class ClearMeasurement(bpy.types.Operator):
|
|||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return len(context.scene.BIMPolylineProperties.measurement_polyline) > 0
|
return len(context.scene.BIMPolylineProperties.measurement_polyline) > 0
|
||||||
|
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
context.scene.BIMPolylineProperties.measurement_polyline.clear()
|
context.scene.BIMPolylineProperties.measurement_polyline.clear()
|
||||||
MeasureDecorator.uninstall()
|
MeasureDecorator.uninstall()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ classes = (
|
|||||||
operator.AddProductivityData,
|
operator.AddProductivityData,
|
||||||
operator.AssignResource,
|
operator.AssignResource,
|
||||||
operator.CalculateResourceWork,
|
operator.CalculateResourceWork,
|
||||||
|
operator.CalculateResourceQuantity,
|
||||||
operator.ConstrainResourceWork,
|
operator.ConstrainResourceWork,
|
||||||
operator.ContractResource,
|
operator.ContractResource,
|
||||||
operator.DisableEditingResource,
|
operator.DisableEditingResource,
|
||||||
|
|||||||
@@ -189,9 +189,13 @@ class CalculateResourceWork(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
active_resource = tool.Resource.get_highlighted_resource()
|
active_resource = tool.Resource.get_highlighted_resource()
|
||||||
if active_resource:
|
if not active_resource:
|
||||||
if tool.Resource.get_productivity(active_resource, should_inherit=True):
|
cls.poll_message_set("No resource is active.")
|
||||||
return True
|
return False
|
||||||
|
if not tool.Resource.get_productivity(active_resource, should_inherit=True):
|
||||||
|
cls.poll_message_set("No productivity data for active resource.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||||
@@ -345,7 +349,6 @@ class ImportResources(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
|
|||||||
|
|
||||||
class AddProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
class AddProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_productivity_data"
|
bl_idname = "bim.add_productivity_data"
|
||||||
bl_description = "Apply"
|
|
||||||
bl_label = "Add Productivity"
|
bl_label = "Add Productivity"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@@ -355,7 +358,6 @@ class AddProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
class EditProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
class EditProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.edit_productivity_data"
|
bl_idname = "bim.edit_productivity_data"
|
||||||
bl_description = "Apply"
|
|
||||||
bl_label = "Edit Productivity"
|
bl_label = "Edit Productivity"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@@ -415,13 +417,27 @@ class CalculateResourceUsage(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
active_resource = tool.Resource.get_highlighted_resource()
|
active_resource = tool.Resource.get_highlighted_resource()
|
||||||
if active_resource:
|
if not active_resource:
|
||||||
if active_resource.Usage and active_resource.Usage.ScheduleWork:
|
cls.poll_message_set("No resource is active.")
|
||||||
task = tool.Resource.get_task_assignments(active_resource)
|
return False
|
||||||
if task and tool.Sequence.has_duration(task):
|
if active_resource.Usage and active_resource.Usage.ScheduleWork:
|
||||||
return True
|
task = tool.Resource.get_task_assignments(active_resource)
|
||||||
|
if task and tool.Sequence.has_duration(task):
|
||||||
|
return True
|
||||||
|
cls.poll_message_set("No usage data for active resource.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.calculate_resource_usage(tool.Ifc, tool.Resource, resource=tool.Resource.get_highlighted_resource())
|
core.calculate_resource_usage(tool.Ifc, tool.Resource, resource=tool.Resource.get_highlighted_resource())
|
||||||
|
|
||||||
|
|
||||||
|
class CalculateResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.calculate_resource_quantity"
|
||||||
|
bl_label = "Calculate Resource Quantity"
|
||||||
|
bl_description = "Calcule resource quantity based on the same name quantities from the output products"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
resource: bpy.props.IntProperty(name="Resource ID")
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.calculate_resource_quantity(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -121,10 +121,11 @@ class BIM_PT_resources(Panel):
|
|||||||
col3.ui_units_x = 2
|
col3.ui_units_x = 2
|
||||||
|
|
||||||
row1_col1 = col1.row()
|
row1_col1 = col1.row()
|
||||||
row1_col1.label(text="Schedule Work")
|
|
||||||
row1col2 = col2.row()
|
|
||||||
schedule_work = resource.get("ScheduleWork", None)
|
schedule_work = resource.get("ScheduleWork", None)
|
||||||
derived_schedule_work = resource.get("DerivedScheduleWork", None)
|
derived_schedule_work = resource.get("DerivedScheduleWork", None)
|
||||||
|
derived_str = "" if schedule_work else " (Derived)"
|
||||||
|
row1_col1.label(text=f"Schedule Work {derived_str}")
|
||||||
|
row1col2 = col2.row()
|
||||||
row1col2.label(
|
row1col2.label(
|
||||||
text="{}".format(schedule_work) if schedule_work else "{} h*".format(derived_schedule_work),
|
text="{}".format(schedule_work) if schedule_work else "{} h*".format(derived_schedule_work),
|
||||||
icon="TIME",
|
icon="TIME",
|
||||||
@@ -258,6 +259,9 @@ class BIM_PT_resources(Panel):
|
|||||||
else:
|
else:
|
||||||
op = row.operator("bim.enable_editing_resource_quantity", text="", icon="GREASEPENCIL")
|
op = row.operator("bim.enable_editing_resource_quantity", text="", icon="GREASEPENCIL")
|
||||||
op.resource = self.props.active_resource_id
|
op.resource = self.props.active_resource_id
|
||||||
|
if resource["type"] == "IfcConstructionMaterialResource":
|
||||||
|
op = row.operator("bim.calculate_resource_quantity", text="", icon="FILE_REFRESH")
|
||||||
|
op.resource = self.props.active_resource_id
|
||||||
op = row.operator("bim.remove_resource_quantity", text="", icon="X")
|
op = row.operator("bim.remove_resource_quantity", text="", icon="X")
|
||||||
op.resource = self.props.active_resource_id
|
op.resource = self.props.active_resource_id
|
||||||
|
|
||||||
|
|||||||
@@ -510,6 +510,10 @@ class AssignProcess(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
related_object_type: bpy.props.StringProperty()
|
related_object_type: bpy.props.StringProperty()
|
||||||
related_object: bpy.props.IntProperty()
|
related_object: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def description(cls, context, properties):
|
||||||
|
return f"Assign selected {properties.related_object_type} to the selected task"
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
if self.related_object_type == "RESOURCE":
|
if self.related_object_type == "RESOURCE":
|
||||||
core.assign_resource(tool.Ifc, tool.Sequence, tool.Resource, task=tool.Ifc.get().by_id(self.task))
|
core.assign_resource(tool.Ifc, tool.Sequence, tool.Resource, task=tool.Ifc.get().by_id(self.task))
|
||||||
@@ -537,6 +541,10 @@ class UnassignProcess(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
related_object: bpy.props.IntProperty()
|
related_object: bpy.props.IntProperty()
|
||||||
resource: bpy.props.IntProperty()
|
resource: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def description(cls, context, properties):
|
||||||
|
return f"Unassign selected {properties.related_object_type} from the selected task"
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
if self.related_object_type == "RESOURCE":
|
if self.related_object_type == "RESOURCE":
|
||||||
core.unassign_resource(
|
core.unassign_resource(
|
||||||
|
|||||||
@@ -90,22 +90,24 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
core.assign_container(tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj)
|
core.assign_container(tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj)
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class EnableEditingContainer(bpy.types.Operator):
|
||||||
bl_idname = "bim.enable_editing_container"
|
bl_idname = "bim.enable_editing_container"
|
||||||
bl_label = "Enable Editing Container"
|
bl_label = "Enable Editing Container"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
core.enable_editing_container(tool.Spatial, obj=context.active_object)
|
core.enable_editing_container(tool.Spatial, obj=context.active_object)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class DisableEditingContainer(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_editing_container"
|
bl_idname = "bim.disable_editing_container"
|
||||||
bl_label = "Disable Editing Container"
|
bl_label = "Disable Editing Container"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
core.disable_editing_container(tool.Spatial, obj=context.active_object)
|
core.disable_editing_container(tool.Spatial, obj=context.active_object)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RemoveContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class RemoveContainer(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -155,7 +157,7 @@ class CopyToContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bonsai.bim.handler.refresh_ui_data()
|
bonsai.bim.handler.refresh_ui_data()
|
||||||
|
|
||||||
|
|
||||||
class SelectContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class SelectContainer(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_container"
|
bl_idname = "bim.select_container"
|
||||||
bl_label = "Select Container"
|
bl_label = "Select Container"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -172,13 +174,13 @@ class SelectContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
self.selection_mode = "SINGLE"
|
self.selection_mode = "SINGLE"
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
if self.container:
|
if self.container:
|
||||||
container = tool.Ifc.get().by_id(self.container)
|
container = tool.Ifc.get().by_id(self.container)
|
||||||
elif element := tool.Ifc.get_entity(context.active_object):
|
elif element := tool.Ifc.get_entity(context.active_object):
|
||||||
container = ifcopenshell.util.element.get_container(element)
|
container = ifcopenshell.util.element.get_container(element)
|
||||||
else:
|
else:
|
||||||
return
|
return {"CANCELLED"}
|
||||||
if container:
|
if container:
|
||||||
core.select_container(
|
core.select_container(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -186,15 +188,17 @@ class SelectContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
container=container,
|
container=container,
|
||||||
selection_mode=self.selection_mode,
|
selection_mode=self.selection_mode,
|
||||||
)
|
)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SelectSimilarContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class SelectSimilarContainer(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_similar_container"
|
bl_idname = "bim.select_similar_container"
|
||||||
bl_label = "Select Similar Container"
|
bl_label = "Select Similar Container"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
core.select_similar_container(tool.Ifc, tool.Spatial, obj=context.active_object)
|
core.select_similar_container(tool.Ifc, tool.Spatial, obj=context.active_object)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SelectProduct(bpy.types.Operator):
|
class SelectProduct(bpy.types.Operator):
|
||||||
@@ -279,18 +283,19 @@ class ToggleContainerElement(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SelectDecomposedElement(bpy.types.Operator, tool.Ifc.Operator):
|
class SelectDecomposedElement(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_decomposed_element"
|
bl_idname = "bim.select_decomposed_element"
|
||||||
bl_label = "Select Decomposed Element"
|
bl_label = "Select Decomposed Element"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
element: bpy.props.IntProperty()
|
element: bpy.props.IntProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
if self.element:
|
if self.element:
|
||||||
core.select_decomposed_element(tool.Ifc, tool.Spatial, element=tool.Ifc.get().by_id(self.element))
|
core.select_decomposed_element(tool.Ifc, tool.Spatial, element=tool.Ifc.get().by_id(self.element))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
class SelectDecomposedElements(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_decomposed_elements"
|
bl_idname = "bim.select_decomposed_elements"
|
||||||
bl_label = "Select Children"
|
bl_label = "Select Children"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -306,7 +311,7 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
self.should_filter = False
|
self.should_filter = False
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
ifc_file = tool.Ifc.get()
|
ifc_file = tool.Ifc.get()
|
||||||
container = ifc_file.by_id(self.container)
|
container = ifc_file.by_id(self.container)
|
||||||
props = context.scene.BIMSpatialDecompositionProperties
|
props = context.scene.BIMSpatialDecompositionProperties
|
||||||
@@ -315,13 +320,13 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
if not self.should_filter and not element_filter:
|
if not self.should_filter and not element_filter:
|
||||||
tool.Spatial.select_products(tool.Spatial.get_decomposed_elements(container))
|
tool.Spatial.select_products(tool.Spatial.get_decomposed_elements(container))
|
||||||
return
|
return {"CANCELLED"}
|
||||||
|
|
||||||
if props.element_mode == "TYPE":
|
if props.element_mode == "TYPE":
|
||||||
if active_element.type == "OCCURRENCE":
|
if active_element.type == "OCCURRENCE":
|
||||||
if obj := tool.Ifc.get_object(ifc_file.by_id(active_element.ifc_definition_id)):
|
if obj := tool.Ifc.get_object(ifc_file.by_id(active_element.ifc_definition_id)):
|
||||||
tool.Blender.set_active_object(obj)
|
tool.Blender.set_active_object(obj)
|
||||||
return
|
return {"CANCELLED"}
|
||||||
|
|
||||||
ifc_class = relating_type = None
|
ifc_class = relating_type = None
|
||||||
is_untyped = False
|
is_untyped = False
|
||||||
@@ -346,7 +351,7 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if active_element.type == "OCCURRENCE":
|
if active_element.type == "OCCURRENCE":
|
||||||
if obj := tool.Ifc.get_object(ifc_file.by_id(active_element.ifc_definition_id)):
|
if obj := tool.Ifc.get_object(ifc_file.by_id(active_element.ifc_definition_id)):
|
||||||
tool.Blender.set_active_object(obj)
|
tool.Blender.set_active_object(obj)
|
||||||
return
|
return {"CANCELLED"}
|
||||||
|
|
||||||
if active_element.type == "CLASSIFICATION":
|
if active_element.type == "CLASSIFICATION":
|
||||||
identification = active_element.identification
|
identification = active_element.identification
|
||||||
@@ -362,20 +367,22 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
tool.Spatial.select_products(filter(filter_element, elements))
|
tool.Spatial.select_products(filter(filter_element, elements))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SetDefaultContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class SetDefaultContainer(bpy.types.Operator):
|
||||||
bl_idname = "bim.set_default_container"
|
bl_idname = "bim.set_default_container"
|
||||||
bl_label = "Set Default Container"
|
bl_label = "Set Default Container"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
bl_description = "Set this as the default container that all new elements will be contained in"
|
bl_description = "Set this as the default container that all new elements will be contained in"
|
||||||
container: bpy.props.IntProperty()
|
container: bpy.props.IntProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
core.set_default_container(tool.Spatial, container=tool.Ifc.get().by_id(self.container))
|
core.set_default_container(tool.Spatial, container=tool.Ifc.get().by_id(self.container))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class SetContainerVisibility(bpy.types.Operator, tool.Ifc.Operator):
|
class SetContainerVisibility(bpy.types.Operator):
|
||||||
bl_idname = "bim.set_container_visibility"
|
bl_idname = "bim.set_container_visibility"
|
||||||
bl_label = "Set Container Visibility"
|
bl_label = "Set Container Visibility"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -396,11 +403,11 @@ class SetContainerVisibility(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
self.should_include_children = False
|
self.should_include_children = False
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
if self.mode == "ISOLATE":
|
if self.mode == "ISOLATE":
|
||||||
if tool.Ifc.get_schema() == "IFC2X3":
|
if tool.Ifc.get_schema() == "IFC2X3":
|
||||||
containers = tool.Ifc.get().by_type("IfcSpatialStructureElement")
|
containers = tool.Ifc.get().by_type("IfcSpatialStructureElement")
|
||||||
elif tool.Ifc.get_schema() != "IFC2X3":
|
else:
|
||||||
containers = set(tool.Ifc.get().by_type("IfcSpatialElement"))
|
containers = set(tool.Ifc.get().by_type("IfcSpatialElement"))
|
||||||
containers -= set(tool.Ifc.get().by_type("IfcSpatialZone"))
|
containers -= set(tool.Ifc.get().by_type("IfcSpatialZone"))
|
||||||
for container in containers:
|
for container in containers:
|
||||||
@@ -420,29 +427,31 @@ class SetContainerVisibility(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
collection.hide_viewport = should_hide
|
collection.hide_viewport = should_hide
|
||||||
if self.should_include_children:
|
if self.should_include_children:
|
||||||
queue.extend(ifcopenshell.util.element.get_parts(container))
|
queue.extend(ifcopenshell.util.element.get_parts(container))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ToggleGrids(bpy.types.Operator, tool.Ifc.Operator):
|
class ToggleGrids(bpy.types.Operator):
|
||||||
bl_idname = "bim.toggle_grids"
|
bl_idname = "bim.toggle_grids"
|
||||||
bl_label = "Toggle Grids"
|
bl_label = "Toggle Grids"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
bl_description = "Show or hide grids and grid axes"
|
bl_description = "Show or hide grids and grid axes"
|
||||||
is_visible: bpy.props.BoolProperty(name="Is Visible", default=False, options={"SKIP_SAVE"})
|
is_visible: bpy.props.BoolProperty(name="Is Visible", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
for element in tool.Ifc.get().by_type("IfcGrid") + tool.Ifc.get().by_type("IfcGridAxis"):
|
for element in tool.Ifc.get().by_type("IfcGrid") + tool.Ifc.get().by_type("IfcGridAxis"):
|
||||||
if obj := tool.Ifc.get_object(element):
|
if obj := tool.Ifc.get_object(element):
|
||||||
obj.hide_set(not self.is_visible)
|
obj.hide_set(not self.is_visible)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ToggleSpatialElements(bpy.types.Operator, tool.Ifc.Operator):
|
class ToggleSpatialElements(bpy.types.Operator):
|
||||||
bl_idname = "bim.toggle_spatial_elements"
|
bl_idname = "bim.toggle_spatial_elements"
|
||||||
bl_label = "Toggle Spatial Elements"
|
bl_label = "Toggle Spatial Elements"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
bl_description = "Show or hide spatial elements, such as buildings, sites, etc"
|
bl_description = "Show or hide spatial elements, such as buildings, sites, etc"
|
||||||
is_visible: bpy.props.BoolProperty(name="Is Visible", default=False, options={"SKIP_SAVE"})
|
is_visible: bpy.props.BoolProperty(name="Is Visible", default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
def _execute(self, context):
|
def execute(self, context):
|
||||||
if tool.Ifc.get().schema == "IFC2X3":
|
if tool.Ifc.get().schema == "IFC2X3":
|
||||||
elements = tool.Ifc.get().by_type("IfcSpatialStructureElement")
|
elements = tool.Ifc.get().by_type("IfcSpatialStructureElement")
|
||||||
else:
|
else:
|
||||||
@@ -450,3 +459,4 @@ class ToggleSpatialElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
for element in elements:
|
for element in elements:
|
||||||
if obj := tool.Ifc.get_object(element):
|
if obj := tool.Ifc.get_object(element):
|
||||||
obj.hide_set(not self.is_visible)
|
obj.hide_set(not self.is_visible)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def regenerate_sheet(drawing: tool.Drawing, sheet: ifcopenshell.entity_instance)
|
|||||||
drawing.delete_file(path_layout)
|
drawing.delete_file(path_layout)
|
||||||
|
|
||||||
|
|
||||||
def open_sheet(drawing: tool.Drawing, sheet: ifcopenshell.entity_instance) -> None:
|
def open_layout(drawing: tool.Drawing, sheet: ifcopenshell.entity_instance) -> None:
|
||||||
drawing.open_layout_svg(drawing.get_document_uri(sheet, "LAYOUT"))
|
drawing.open_layout_svg(drawing.get_document_uri(sheet, "LAYOUT"))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -262,3 +262,7 @@ def calculate_resource_usage(
|
|||||||
) -> None:
|
) -> None:
|
||||||
ifc.run("resource.calculate_resource_usage", resource=resource)
|
ifc.run("resource.calculate_resource_usage", resource=resource)
|
||||||
resource_tool.load_resources()
|
resource_tool.load_resources()
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_resource_quantity(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None:
|
||||||
|
resource_tool.calculate_resource_quantity(resource)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class Collector(bonsai.core.tool.Collector):
|
|||||||
users_collection.objects.unlink(obj)
|
users_collection.objects.unlink(obj)
|
||||||
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
assert element
|
||||||
|
|
||||||
# Note that tool.Geometry.is_locked is only checked within the if
|
# Note that tool.Geometry.is_locked is only checked within the if
|
||||||
# statements for efficiency as it is a slow check.
|
# statements for efficiency as it is a slow check.
|
||||||
|
|||||||
@@ -774,7 +774,9 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
def import_drawings(cls) -> None:
|
def import_drawings(cls) -> None:
|
||||||
props = bpy.context.scene.DocProperties
|
props = bpy.context.scene.DocProperties
|
||||||
expanded_target_views = {d.target_view for d in props.drawings if d.is_expanded}
|
expanded_target_views = {d.target_view for d in props.drawings if d.is_expanded}
|
||||||
current_drawings_selection = {d.ifc_definition_id: d.is_selected for d in props.drawings}
|
if not hasattr(cls, "drawing_selected_states"):
|
||||||
|
cls.drawing_selected_states = {}
|
||||||
|
cls.drawing_selected_states.update({d.ifc_definition_id: d.is_selected for d in props.drawings if d.is_drawing})
|
||||||
props.drawings.clear()
|
props.drawings.clear()
|
||||||
drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
|
drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
|
||||||
grouped_drawings = {
|
grouped_drawings = {
|
||||||
@@ -801,7 +803,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
for drawing in sorted(drawings, key=lambda x: x.Name or "Unnamed"):
|
for drawing in sorted(drawings, key=lambda x: x.Name or "Unnamed"):
|
||||||
new = props.drawings.add()
|
new = props.drawings.add()
|
||||||
new.name = drawing.Name or "Unnamed"
|
new.name = drawing.Name or "Unnamed"
|
||||||
new.is_selected = current_drawings_selection.get(drawing.id(), True)
|
new.is_selected = cls.drawing_selected_states.setdefault(drawing.id(), True)
|
||||||
new.is_drawing = True
|
new.is_drawing = True
|
||||||
new.ifc_definition_id = drawing.id() # Last, to prevent unnecessary prop callbacks
|
new.ifc_definition_id = drawing.id() # Last, to prevent unnecessary prop callbacks
|
||||||
|
|
||||||
@@ -828,6 +830,9 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
def import_sheets(cls) -> None:
|
def import_sheets(cls) -> None:
|
||||||
props = bpy.context.scene.DocProperties
|
props = bpy.context.scene.DocProperties
|
||||||
expanded_sheets = {s.ifc_definition_id for s in props.sheets if s.is_expanded}
|
expanded_sheets = {s.ifc_definition_id for s in props.sheets if s.is_expanded}
|
||||||
|
if not hasattr(cls, "sheet_selected_states"):
|
||||||
|
cls.sheet_selected_states = {}
|
||||||
|
cls.sheet_selected_states.update({s.ifc_definition_id: s.is_selected for s in props.sheets if s.is_sheet})
|
||||||
props.sheets.clear()
|
props.sheets.clear()
|
||||||
sheets = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SHEET"]
|
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))):
|
for sheet in sorted(sheets, key=lambda s: getattr(s, "Identification", getattr(s, "DocumentId", None))):
|
||||||
@@ -840,6 +845,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
new.name = sheet.Name
|
new.name = sheet.Name
|
||||||
new.is_sheet = True
|
new.is_sheet = True
|
||||||
new.is_expanded = sheet.id() in expanded_sheets
|
new.is_expanded = sheet.id() in expanded_sheets
|
||||||
|
new.is_selected = cls.sheet_selected_states.setdefault(sheet.id(), True)
|
||||||
|
|
||||||
if not new.is_expanded:
|
if not new.is_expanded:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -747,7 +747,10 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
meshes[mesh_name] = mesh
|
meshes[mesh_name] = mesh
|
||||||
|
|
||||||
old_mesh = obj.data
|
old_mesh = obj.data
|
||||||
cls.change_object_data(obj, mesh, is_global=False)
|
if type(old_mesh) == type(mesh):
|
||||||
|
cls.change_object_data(obj, mesh, is_global=False)
|
||||||
|
else:
|
||||||
|
obj = cls.recreate_object_with_data(obj, mesh, is_global=False)
|
||||||
cls.record_object_materials(obj)
|
cls.record_object_materials(obj)
|
||||||
if not cls.has_data_users(old_mesh):
|
if not cls.has_data_users(old_mesh):
|
||||||
cls.delete_data(old_mesh)
|
cls.delete_data(old_mesh)
|
||||||
@@ -778,7 +781,10 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
meshes[mesh_name] = mesh
|
meshes[mesh_name] = mesh
|
||||||
|
|
||||||
old_mesh = obj.data
|
old_mesh = obj.data
|
||||||
cls.change_object_data(obj, mesh, is_global=False)
|
if type(old_mesh) == type(mesh):
|
||||||
|
cls.change_object_data(obj, mesh, is_global=False)
|
||||||
|
else:
|
||||||
|
obj = cls.recreate_object_with_data(obj, mesh, is_global=False)
|
||||||
cls.record_object_materials(obj)
|
cls.record_object_materials(obj)
|
||||||
if not cls.has_data_users(old_mesh):
|
if not cls.has_data_users(old_mesh):
|
||||||
cls.delete_data(old_mesh)
|
cls.delete_data(old_mesh)
|
||||||
|
|||||||
@@ -443,6 +443,12 @@ class Resource(bonsai.core.tool.Resource):
|
|||||||
def run_calculate_resource_usage(cls, resource: ifcopenshell.entity_instance) -> None:
|
def run_calculate_resource_usage(cls, resource: ifcopenshell.entity_instance) -> None:
|
||||||
tool.Ifc.run("resource.calculate_resource_usage", resource=resource)
|
tool.Ifc.run("resource.calculate_resource_usage", resource=resource)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def calculate_resource_quantity(cls, resource: ifcopenshell.entity_instance) -> None:
|
||||||
|
quantity: ifcopenshell.entity_instance = resource.BaseQuantity
|
||||||
|
quantity_from_products = ifcopenshell.util.resource.get_total_quantity_produced(resource, quantity.Name)
|
||||||
|
quantity[3] = quantity_from_products
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_task_assignments(cls, resource: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
def get_task_assignments(cls, resource: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
return ifcopenshell.util.resource.get_task_assignments(resource)
|
return ifcopenshell.util.resource.get_task_assignments(resource)
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ def calculate_cost_item_resource_value(file: ifcopenshell.file, cost_item: ifcop
|
|||||||
|
|
||||||
for resource in resources:
|
for resource in resources:
|
||||||
cost, unit = ifcopenshell.util.resource.get_cost(resource)
|
cost, unit = ifcopenshell.util.resource.get_cost(resource)
|
||||||
|
# TODO: cost is never None because get_cost always returns a float.
|
||||||
if cost is None:
|
if cost is None:
|
||||||
# Concept to standardise - Not defined in schema, but this makes manual scheduling of resources 10x faster and less duplicate data.
|
# Concept to standardise - Not defined in schema, but this makes manual scheduling of resources 10x faster and less duplicate data.
|
||||||
parent_cost = ifcopenshell.util.resource.get_parent_cost(resource)
|
parent_cost = ifcopenshell.util.resource.get_parent_cost(resource)
|
||||||
|
|||||||
@@ -36,22 +36,25 @@ def remove_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_insta
|
|||||||
"""
|
"""
|
||||||
settings = {"resource": resource}
|
settings = {"resource": resource}
|
||||||
|
|
||||||
|
def remove_consider_history(root: ifcopenshell.entity_instance) -> None:
|
||||||
|
history = root.OwnerHistory
|
||||||
|
file.remove(root)
|
||||||
|
if history:
|
||||||
|
ifcopenshell.util.element.remove_deep2(file, history)
|
||||||
|
|
||||||
# TODO: review deep purge
|
# TODO: review deep purge
|
||||||
for inverse in file.get_inverse(settings["resource"]):
|
for inverse in file.get_inverse(settings["resource"]):
|
||||||
if inverse.is_a("IfcRelNests"):
|
if inverse.is_a("IfcRelNests"):
|
||||||
if inverse.RelatingObject == settings["resource"]:
|
if inverse.RelatingObject == settings["resource"]:
|
||||||
for related_object in inverse.RelatedObjects:
|
for related_object in inverse.RelatedObjects:
|
||||||
ifcopenshell.api.resource.remove_resource(file, resource=related_object)
|
ifcopenshell.api.resource.remove_resource(file, resource=related_object)
|
||||||
history = inverse.OwnerHistory
|
remove_consider_history(inverse)
|
||||||
file.remove(inverse)
|
elif inverse.RelatedObjects == (resource,):
|
||||||
if history:
|
remove_consider_history(inverse)
|
||||||
ifcopenshell.util.element.remove_deep2(file, history)
|
|
||||||
elif inverse.is_a("IfcRelAssignsToControl"):
|
elif inverse.is_a("IfcRelAssignsToControl"):
|
||||||
if len(inverse.RelatedObjects) == 1:
|
if len(inverse.RelatedObjects) == 1:
|
||||||
history = inverse.OwnerHistory
|
remove_consider_history(inverse)
|
||||||
file.remove(inverse)
|
|
||||||
if history:
|
|
||||||
ifcopenshell.util.element.remove_deep2(file, history)
|
|
||||||
else:
|
else:
|
||||||
related_objects = list(inverse.RelatedObjects)
|
related_objects = list(inverse.RelatedObjects)
|
||||||
related_objects.remove(settings["resource"])
|
related_objects.remove(settings["resource"])
|
||||||
@@ -62,17 +65,11 @@ def remove_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_insta
|
|||||||
ifcopenshell.api.resource.unassign_resource(
|
ifcopenshell.api.resource.unassign_resource(
|
||||||
file, related_object=related_object, relating_resource=settings["resource"]
|
file, related_object=related_object, relating_resource=settings["resource"]
|
||||||
)
|
)
|
||||||
elif inverse.RelatedObjects == tuple(settings["resource"]):
|
elif inverse.RelatedObjects == (resource,):
|
||||||
history = inverse.OwnerHistory
|
remove_consider_history(inverse)
|
||||||
file.remove(inverse)
|
|
||||||
if history:
|
|
||||||
ifcopenshell.util.element.remove_deep2(file, history)
|
|
||||||
# Usage was added in IFC4.
|
# Usage was added in IFC4.
|
||||||
if usage := getattr(settings["resource"], "Usage", None):
|
if usage := getattr(settings["resource"], "Usage", None):
|
||||||
file.remove(usage)
|
file.remove(usage)
|
||||||
if settings["resource"].BaseQuantity:
|
if settings["resource"].BaseQuantity:
|
||||||
ifcopenshell.api.resource.remove_resource_quantity(file, resource=settings["resource"])
|
ifcopenshell.api.resource.remove_resource_quantity(file, resource=settings["resource"])
|
||||||
history = settings["resource"].OwnerHistory
|
remove_consider_history(resource)
|
||||||
file.remove(settings["resource"])
|
|
||||||
if history:
|
|
||||||
ifcopenshell.util.element.remove_deep2(file, history)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user