mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 18:43:26 +00:00
Merge branch 'v0.7.0' into fix_bug
This commit is contained in:
@@ -174,9 +174,8 @@ def unregister():
|
||||
for cls in reversed(classes):
|
||||
if getattr(cls, "is_registered", None) is None:
|
||||
bpy.utils.unregister_class(cls)
|
||||
else:
|
||||
if cls.is_registered is not False:
|
||||
bpy.utils.unregister_class(cls)
|
||||
elif cls.is_registered:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
|
||||
@@ -30,7 +30,9 @@ classes = (
|
||||
operator.AddSchedule,
|
||||
operator.AddScheduleToSheet,
|
||||
operator.AddSheet,
|
||||
operator.AddTextLiteral,
|
||||
operator.BuildSchedule,
|
||||
operator.ChangeSheetTitleBlock,
|
||||
operator.CleanWireframes,
|
||||
operator.ContractSheet,
|
||||
operator.CreateDrawing,
|
||||
@@ -40,8 +42,6 @@ classes = (
|
||||
operator.DisableEditingSchedules,
|
||||
operator.DisableEditingSheets,
|
||||
operator.DisableEditingText,
|
||||
operator.AddTextLiteral,
|
||||
operator.RemoveTextLiteral,
|
||||
operator.DuplicateDrawing,
|
||||
operator.EditAssignedProduct,
|
||||
operator.EditText,
|
||||
@@ -53,20 +53,21 @@ classes = (
|
||||
operator.LoadDrawings,
|
||||
operator.LoadSchedules,
|
||||
operator.LoadSheets,
|
||||
operator.OpenDrawing,
|
||||
operator.OpenSchedule,
|
||||
operator.OpenSheet,
|
||||
operator.ChangeSheetTitleBlock,
|
||||
operator.OpenView,
|
||||
operator.RemoveDrawing,
|
||||
operator.RemoveDrawingFromSheet,
|
||||
operator.RemoveDrawingStyle,
|
||||
operator.RemoveDrawingStyleAttribute,
|
||||
operator.RemoveSchedule,
|
||||
operator.RemoveSheet,
|
||||
operator.RemoveTextLiteral,
|
||||
operator.RenameSheet,
|
||||
operator.ResizeText,
|
||||
operator.SaveDrawingStyle,
|
||||
operator.SelectDocIfcFile,
|
||||
operator.SelectAssignedProduct,
|
||||
operator.SelectDocIfcFile,
|
||||
prop.Variable,
|
||||
prop.Drawing,
|
||||
prop.Schedule,
|
||||
|
||||
@@ -61,7 +61,7 @@ class SheetsData:
|
||||
|
||||
@classmethod
|
||||
def total_sheets(cls):
|
||||
return len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"])
|
||||
return len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SHEET"])
|
||||
|
||||
|
||||
class DrawingsData:
|
||||
|
||||
@@ -159,9 +159,13 @@ class BaseDecorator:
|
||||
"BATTING",
|
||||
)
|
||||
for obj in collection.all_objects:
|
||||
if obj.hide_get():
|
||||
continue
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
|
||||
if element.is_a("IfcAnnotation"):
|
||||
if element.ObjectType == self.objecttype:
|
||||
results.append(obj)
|
||||
|
||||
@@ -245,7 +245,7 @@ class CreateDrawing(bpy.types.Operator):
|
||||
elif "</svg>" in line:
|
||||
continue
|
||||
outfile.write(line)
|
||||
shutil.copyfile(underlay[0:-4] + ".png", svg_path[0:-4] + "-underlay.png")
|
||||
shutil.copyfile(os.path.splitext(underlay)[0] + ".png", os.path.splitext(svg_path)[0] + "-underlay.png")
|
||||
if linework:
|
||||
with open(linework) as infile:
|
||||
should_skip = False
|
||||
@@ -605,6 +605,9 @@ class CreateDrawing(bpy.types.Operator):
|
||||
return svg_path
|
||||
|
||||
elements = tool.Drawing.get_group_elements(tool.Drawing.get_drawing_group(self.camera_element))
|
||||
filtered_drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element)
|
||||
elements = [e for e in elements if e in filtered_drawing_elements]
|
||||
|
||||
annotations = sorted(elements, key=lambda a: tool.Drawing.get_annotation_z_index(a))
|
||||
|
||||
self.svg_writer.metadata = tool.Drawing.get_drawing_metadata(self.camera_element)
|
||||
@@ -736,29 +739,24 @@ class AddDrawingToSheet(bpy.types.Operator, Operator):
|
||||
|
||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
||||
if not sheet.is_a("IfcDocumentInformation"):
|
||||
return {"FINISHED"}
|
||||
return
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences or []
|
||||
else:
|
||||
references = sheet.HasDocumentReferences or []
|
||||
references = tool.Drawing.get_document_references(sheet)
|
||||
|
||||
has_drawing = False
|
||||
for reference in references:
|
||||
if reference.Location == drawing_reference.Location:
|
||||
has_drawing = True
|
||||
break
|
||||
|
||||
if has_drawing:
|
||||
return {"FINISHED"}
|
||||
return
|
||||
|
||||
if not tool.Drawing.does_file_exist(tool.Drawing.get_document_uri(drawing_reference)):
|
||||
self.report({"ERROR"}, "The drawing must be generated before adding to a sheet.")
|
||||
return
|
||||
|
||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences
|
||||
id_attr = "ItemReference"
|
||||
else:
|
||||
references = sheet.HasDocumentReferences
|
||||
id_attr = "Identification"
|
||||
id_attr = "ItemReference" if tool.Ifc.get_schema() == "IFC2X3" else "Identification"
|
||||
attributes = {
|
||||
id_attr: str(len([r for r in references if r.Description in ("DRAWING", "SCHEDULE")]) + 1),
|
||||
"Location": drawing_reference.Location,
|
||||
@@ -770,16 +768,15 @@ class AddDrawingToSheet(bpy.types.Operator, Operator):
|
||||
sheet_builder.add_drawing(reference, drawing, sheet)
|
||||
|
||||
tool.Drawing.import_sheets()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveDrawingFromSheet(bpy.types.Operator):
|
||||
class RemoveDrawingFromSheet(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_drawing_from_sheet"
|
||||
bl_label = "Remove Drawing From Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
reference: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
def _execute(self, context):
|
||||
reference = tool.Ifc.get().by_id(self.reference)
|
||||
sheet = tool.Drawing.get_reference_document(reference)
|
||||
|
||||
@@ -787,48 +784,55 @@ class RemoveDrawingFromSheet(bpy.types.Operator):
|
||||
sheet_builder.data_dir = context.scene.BIMProperties.data_dir
|
||||
sheet_builder.remove_drawing(reference, sheet)
|
||||
|
||||
drawing = tool.Drawing.get_reference_element(reference)
|
||||
if drawing:
|
||||
tool.Ifc.run("document.unassign_document", product=drawing, document=reference)
|
||||
|
||||
tool.Ifc.run("document.remove_reference", reference=reference)
|
||||
|
||||
tool.Drawing.import_sheets()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CreateSheets(bpy.types.Operator):
|
||||
class CreateSheets(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.create_sheets"
|
||||
bl_label = "Create Sheets"
|
||||
# TODO: check undo redo
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.scene.DocProperties.sheets and context.scene.BIMProperties.data_dir
|
||||
|
||||
def execute(self, context):
|
||||
def _execute(self, context):
|
||||
scene = context.scene
|
||||
props = scene.DocProperties
|
||||
active_sheet = props.sheets[props.active_sheet_index]
|
||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
||||
|
||||
if not sheet.is_a("IfcDocumentInformation"):
|
||||
return {"FINISHED"}
|
||||
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 = sheet_builder.build(sheet)
|
||||
svg = references["SHEET"]
|
||||
basename = os.path.basename(svg)
|
||||
path = os.path.dirname(svg)
|
||||
pdf = os.path.splitext(svg)[0] + ".pdf"
|
||||
eps = os.path.splitext(svg)[0] + ".eps"
|
||||
dxf = os.path.splitext(svg)[0] + ".dxf"
|
||||
|
||||
references = getattr(sheet, "HasDocumentReferences", getattr(sheet, "DocumentReferences", []))
|
||||
if not [r for r in references if r.Description == "SHEET"]:
|
||||
has_sheet_reference = False
|
||||
for reference in tool.Drawing.get_document_references(sheet):
|
||||
if reference.Description == "SHEET":
|
||||
has_sheet_reference = True
|
||||
elif reference.Description == "RASTER":
|
||||
if reference.Location in raster_references:
|
||||
del raster_references[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",
|
||||
@@ -836,6 +840,14 @@ class CreateSheets(bpy.types.Operator):
|
||||
attributes={"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={"Location": tool.Ifc.get_relative_uri(raster_reference), "Description": "RASTER"},
|
||||
)
|
||||
|
||||
svg2pdf_command = context.preferences.addons["blenderbim"].preferences.svg2pdf_command
|
||||
svg2dxf_command = context.preferences.addons["blenderbim"].preferences.svg2dxf_command
|
||||
|
||||
@@ -857,37 +869,43 @@ class CreateSheets(bpy.types.Operator):
|
||||
open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf)
|
||||
else:
|
||||
open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ChangeSheetTitleBlock(bpy.types.Operator):
|
||||
class ChangeSheetTitleBlock(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.change_sheet_title_block"
|
||||
bl_label = "Change Sheet Title Block"
|
||||
bl_description = "Change the title block of the active sheet"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def execute(self, context):
|
||||
def _execute(self, context):
|
||||
scene = context.scene
|
||||
props = scene.DocProperties
|
||||
|
||||
if not len(props.sheets):
|
||||
return {"CANCELLED"}
|
||||
|
||||
titleblock = scene.DocProperties.titleblock
|
||||
|
||||
active_sheet = props.sheets[props.active_sheet_index]
|
||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
||||
|
||||
for reference in tool.Drawing.get_document_references(sheet):
|
||||
description = tool.Drawing.get_reference_description(reference)
|
||||
if description == "TITLEBLOCK":
|
||||
tool.Ifc.run(
|
||||
"document.edit_reference",
|
||||
reference=reference,
|
||||
attributes={"Location": tool.Drawing.get_default_titleblock_path(titleblock)},
|
||||
)
|
||||
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = scene.BIMProperties.data_dir
|
||||
titleblock = scene.DocProperties.titleblock
|
||||
sheet_builder.change_titleblock(sheet, titleblock)
|
||||
|
||||
self.report({"INFO"}, 'Title block changed for sheet "{}" to {}'.format(sheet.Name, titleblock))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class OpenView(bpy.types.Operator):
|
||||
bl_idname = "bim.open_view"
|
||||
bl_label = "Open View"
|
||||
class OpenDrawing(bpy.types.Operator):
|
||||
bl_idname = "bim.open_drawing"
|
||||
bl_label = "Open Drawing"
|
||||
view: bpy.props.StringProperty()
|
||||
bl_description = (
|
||||
"Opens a .svg drawing based on currently active camera with default system viewer\n"
|
||||
@@ -1226,27 +1244,22 @@ class AddScheduleToSheet(bpy.types.Operator, Operator):
|
||||
if not sheet.is_a("IfcDocumentInformation"):
|
||||
return
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences or []
|
||||
else:
|
||||
references = sheet.HasDocumentReferences or []
|
||||
references = tool.Drawing.get_document_references(sheet)
|
||||
|
||||
has_schedule = False
|
||||
for reference in references:
|
||||
if reference.Location == schedule_location:
|
||||
has_schedule = True
|
||||
break
|
||||
|
||||
if has_schedule:
|
||||
return
|
||||
|
||||
if not tool.Drawing.does_file_exist(tool.Ifc.resolve_uri(schedule_location)):
|
||||
self.report({"ERROR"}, "The schedule must be generated before adding to a sheet.")
|
||||
return
|
||||
|
||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences
|
||||
id_attr = "ItemReference"
|
||||
else:
|
||||
references = sheet.HasDocumentReferences
|
||||
id_attr = "Identification"
|
||||
id_attr = "ItemReference" if tool.Ifc.get_schema() == "IFC2X3" else "Identification"
|
||||
attributes = {
|
||||
id_attr: str(len([r for r in references if r.Description in ("DRAWING", "SCHEDULE")]) + 1),
|
||||
"Location": schedule_location,
|
||||
@@ -1456,7 +1469,7 @@ class EditAssignedProduct(bpy.types.Operator, Operator):
|
||||
|
||||
class EnableEditingAssignedProduct(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.enable_editing_assigned_product"
|
||||
bl_label = "Enable Editing Text Product"
|
||||
bl_label = "Enable Editing Assigned Product"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -1465,7 +1478,7 @@ class EnableEditingAssignedProduct(bpy.types.Operator, Operator):
|
||||
|
||||
class DisableEditingAssignedProduct(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_assigned_product"
|
||||
bl_label = "Disable Editing Text Product"
|
||||
bl_label = "Disable Editing Assigned Product"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -1498,9 +1511,36 @@ class LoadSheets(bpy.types.Operator, Operator):
|
||||
self.report({"ERROR"}, "Some sheets svg files are missing:\n" + "\n".join(sheets_not_found))
|
||||
|
||||
|
||||
class RenameSheet(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.rename_sheet"
|
||||
bl_label = "Rename Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
identification: bpy.props.StringProperty()
|
||||
name: bpy.props.StringProperty()
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.props = context.scene.DocProperties
|
||||
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
||||
self.identification = sheet.Identification
|
||||
self.name = sheet.Name
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
row = self.layout.row()
|
||||
row.prop(self, "identification", text="Identification")
|
||||
row = self.layout.row()
|
||||
row.prop(self, "name", text="Name")
|
||||
|
||||
def _execute(self, context):
|
||||
self.props = context.scene.DocProperties
|
||||
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
||||
core.rename_sheet(tool.Ifc, tool.Drawing, sheet=sheet, identification=self.identification, name=self.name)
|
||||
tool.Drawing.import_sheets()
|
||||
|
||||
|
||||
class DisableEditingSheets(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_sheets"
|
||||
bl_label = "Disable Editing Text Product"
|
||||
bl_label = "Disable Editing Sheets"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -1518,7 +1558,7 @@ class LoadSchedules(bpy.types.Operator, Operator):
|
||||
|
||||
class DisableEditingSchedules(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_schedules"
|
||||
bl_label = "Disable Editing Text Product"
|
||||
bl_label = "Disable Editing Schedules"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -1536,7 +1576,7 @@ class LoadDrawings(bpy.types.Operator, Operator):
|
||||
|
||||
class DisableEditingDrawings(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_drawings"
|
||||
bl_label = "Disable Editing Text Product"
|
||||
bl_label = "Disable Editing Drawings"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
|
||||
@@ -248,26 +248,9 @@ class Schedule(PropertyGroup):
|
||||
|
||||
|
||||
class Sheet(PropertyGroup):
|
||||
def set_name(self, new):
|
||||
old = self.get("name")
|
||||
|
||||
if new == old:
|
||||
return
|
||||
sheet = tool.Ifc.get().by_id(self.ifc_definition_id)
|
||||
old_path = Path(tool.Drawing.get_document_uri(sheet))
|
||||
core.update_sheet_name(tool.Ifc, tool.Drawing, sheet=sheet, name=new)
|
||||
self["name"] = new
|
||||
|
||||
new_path = Path(tool.Drawing.get_document_uri(sheet))
|
||||
if old and old_path.is_file():
|
||||
old_path.rename(new_path)
|
||||
|
||||
def get_name(self):
|
||||
return self.get("name")
|
||||
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
identification: StringProperty(name="Identification")
|
||||
name: StringProperty(name="Name", get=get_name, set=set_name)
|
||||
name: StringProperty(name="Name")
|
||||
is_sheet: BoolProperty(name="Is Sheet", default=False)
|
||||
reference_type: StringProperty(name="Reference Type")
|
||||
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
||||
@@ -354,11 +337,15 @@ class DocProperties(PropertyGroup):
|
||||
decorations_colour: FloatVectorProperty(
|
||||
name="Decorations Colour", subtype="COLOR", default=(1, 1, 1, 1), min=0.0, max=1.0, size=4
|
||||
)
|
||||
docs_dir: StringProperty(default=os.path.join("docs") + os.path.sep, name="Default Docs Directory")
|
||||
sheets_dir: StringProperty(default=os.path.join("sheets") + os.path.sep, name="Default Sheets Directory")
|
||||
titleblocks_dir: StringProperty(default=os.path.join("sheets", "titleblocks") + os.path.sep, name="Default Titleblocks Directory")
|
||||
layouts_dir: StringProperty(default=os.path.join("layouts") + os.path.sep, name="Default Layouts Directory")
|
||||
titleblocks_dir: StringProperty(
|
||||
default=os.path.join("layouts", "titleblocks") + os.path.sep, name="Default Titleblocks Directory"
|
||||
)
|
||||
drawings_dir: StringProperty(default=os.path.join("drawings") + os.path.sep, name="Default Drawings Directory")
|
||||
stylesheet_path: StringProperty(default=os.path.join("drawings", "assets", "default.css"), name="Default Stylesheet")
|
||||
stylesheet_path: StringProperty(
|
||||
default=os.path.join("drawings", "assets", "default.css"), name="Default Stylesheet"
|
||||
)
|
||||
markers_path: StringProperty(default=os.path.join("drawings", "assets", "markers.svg"), name="Default Markers")
|
||||
symbols_path: StringProperty(default=os.path.join("drawings", "assets", "symbols.svg"), name="Default Symbols")
|
||||
patterns_path: StringProperty(default=os.path.join("drawings", "assets", "patterns.svg"), name="Default Patterns")
|
||||
|
||||
@@ -34,8 +34,8 @@ class SheetBuilder:
|
||||
self.data_dir = None
|
||||
self.scale = "NTS"
|
||||
|
||||
def create(self, sheet_path, titleblock_name):
|
||||
sheet_dir = os.path.dirname(sheet_path)
|
||||
def create(self, layout_path, titleblock_name):
|
||||
sheet_dir = os.path.dirname(layout_path)
|
||||
|
||||
root = ET.Element("svg")
|
||||
root.attrib["xmlns"] = "http://www.w3.org/2000/svg"
|
||||
@@ -43,16 +43,16 @@ class SheetBuilder:
|
||||
root.attrib["id"] = "root"
|
||||
root.attrib["version"] = "1.1"
|
||||
|
||||
titleblock_path = os.path.join(self.data_dir, "templates", "titleblocks", titleblock_name + ".svg")
|
||||
view_root = ET.parse(titleblock_path).getroot()
|
||||
ootb_titleblock_path = os.path.join(self.data_dir, "templates", "titleblocks", titleblock_name + ".svg")
|
||||
titleblock_path = tool.Ifc.resolve_uri(tool.Drawing.get_default_titleblock_path(titleblock_name))
|
||||
|
||||
view_root = ET.parse(ootb_titleblock_path).getroot()
|
||||
view_width = self.convert_to_mm(view_root.attrib.get("width"))
|
||||
view_height = self.convert_to_mm(view_root.attrib.get("height"))
|
||||
view = ET.SubElement(root, "g")
|
||||
view.attrib["data-type"] = "titleblock"
|
||||
titleblock = ET.SubElement(view, "image")
|
||||
titleblock.attrib["xlink:href"] = os.path.relpath(
|
||||
tool.Drawing.get_default_titleblock_path(titleblock_name), sheet_dir
|
||||
)
|
||||
titleblock.attrib["xlink:href"] = os.path.relpath(titleblock_path, sheet_dir)
|
||||
titleblock.attrib["x"] = "0"
|
||||
titleblock.attrib["y"] = "0"
|
||||
titleblock.attrib["width"] = str(view_width)
|
||||
@@ -63,24 +63,22 @@ class SheetBuilder:
|
||||
root.attrib["viewBox"] = "0 0 {} {}".format(view_width, view_height)
|
||||
|
||||
os.makedirs(sheet_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(sheet_dir, "titleblocks"), exist_ok=True)
|
||||
sheet_titleblock_path = os.path.join(sheet_dir, "titleblocks", titleblock_name + ".svg")
|
||||
if not os.path.exists(sheet_titleblock_path):
|
||||
shutil.copy(titleblock_path, sheet_titleblock_path)
|
||||
with open(sheet_path, "w") as f:
|
||||
os.makedirs(os.path.dirname(titleblock_path), exist_ok=True)
|
||||
if not os.path.exists(titleblock_path):
|
||||
shutil.copy(ootb_titleblock_path, titleblock_path)
|
||||
|
||||
with open(layout_path, "w") as f:
|
||||
f.write(minidom.parseString(ET.tostring(root)).toprettyxml(indent=" "))
|
||||
|
||||
def add_drawing(self, reference, drawing, sheet):
|
||||
filename = drawing.Name
|
||||
sheet_path = tool.Drawing.get_document_uri(sheet)
|
||||
sheet_name = os.path.splitext(os.path.basename(sheet_path))[0]
|
||||
sheet_dir = os.path.dirname(sheet_path)
|
||||
|
||||
drawing_path = tool.Drawing.get_document_uri(tool.Drawing.get_drawing_reference(drawing))
|
||||
drawing_path = tool.Ifc.resolve_uri(drawing_path)
|
||||
underlay_path = os.path.splitext(drawing_path)[0] + "-underlay.png"
|
||||
|
||||
if not os.path.isfile(sheet_path):
|
||||
if not os.path.exists(sheet_path) or not os.path.exists(drawing_path):
|
||||
raise FileNotFoundError
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
@@ -190,18 +188,20 @@ class SheetBuilder:
|
||||
title.attrib["height"] = str(self.convert_to_mm(title_root.attrib.get("height")))
|
||||
|
||||
def build(self, sheet):
|
||||
sheet_path = tool.Drawing.get_document_uri(sheet)
|
||||
sheet_name = os.path.splitext(os.path.basename(sheet_path))[0]
|
||||
self.sheet_dir = os.path.dirname(sheet_path)
|
||||
self.references = {"SHEET": None, "RASTER": []}
|
||||
|
||||
docs_dir = tool.Ifc.resolve_uri(os.path.join(bpy.context.scene.DocProperties.docs_dir, sheet_name))
|
||||
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
|
||||
self.layout_dir = os.path.dirname(layout_path)
|
||||
|
||||
os.makedirs(docs_dir, exist_ok=True)
|
||||
output_filename = tool.Ifc.resolve_uri(tool.Drawing.get_default_sheet_path(sheet[0], sheet.Name))
|
||||
self.sheets_dir = os.path.dirname(output_filename)
|
||||
|
||||
os.makedirs(self.sheets_dir, exist_ok=True)
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
ET.register_namespace("xlink", "http://www.w3.org/1999/xlink")
|
||||
|
||||
tree = ET.parse(sheet_path)
|
||||
tree = ET.parse(layout_path)
|
||||
root = tree.getroot()
|
||||
|
||||
self.defs = ET.Element("defs")
|
||||
@@ -211,12 +211,12 @@ class SheetBuilder:
|
||||
self.build_drawings(root, sheet)
|
||||
self.build_schedules(root)
|
||||
|
||||
output_filename = os.path.join(docs_dir, f"{sheet_name}.svg")
|
||||
|
||||
with open(output_filename, "wb") as output:
|
||||
tree.write(output)
|
||||
|
||||
return output_filename
|
||||
self.references["SHEET"] = output_filename
|
||||
|
||||
return self.references
|
||||
|
||||
def build_titleblock(self, root, sheet):
|
||||
titleblock = root.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0]
|
||||
@@ -232,8 +232,6 @@ class SheetBuilder:
|
||||
titleblock.remove(image)
|
||||
|
||||
def build_drawings(self, root, sheet):
|
||||
sheet_name = os.path.splitext(os.path.basename(tool.Drawing.get_document_uri(sheet)))[0]
|
||||
|
||||
for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="drawing"]'):
|
||||
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
|
||||
drawing = tool.Ifc.get().by_id(view.attrib["data-drawing"])
|
||||
@@ -256,8 +254,10 @@ class SheetBuilder:
|
||||
view.append(self.parse_embedded_svg(foreground, {}))
|
||||
|
||||
if background is not None:
|
||||
background_path = os.path.join(self.data_dir, "sheets", self.get_href(background))
|
||||
shutil.copy(background_path, os.path.join(self.data_dir, "build", sheet_name))
|
||||
background_path = os.path.join(self.layout_dir, self.get_href(background))
|
||||
raster_path = os.path.join(self.sheets_dir, os.path.basename(background_path))
|
||||
shutil.copy(background_path, raster_path)
|
||||
self.references["RASTER"].append(raster_path)
|
||||
|
||||
if view_title is not None:
|
||||
foreground_path = self.get_href(foreground)
|
||||
@@ -322,7 +322,7 @@ class SheetBuilder:
|
||||
self.defs.append(clip_path)
|
||||
|
||||
svg_path = self.get_href(image)
|
||||
with open(os.path.join(self.sheet_dir, svg_path), "r") as template:
|
||||
with open(os.path.join(self.layout_dir, svg_path), "r") as template:
|
||||
embedded = ET.fromstring(pystache.render(template.read(), data))
|
||||
# viewBox should not be nested
|
||||
embedded.attrib["viewBox"] = ""
|
||||
@@ -339,23 +339,29 @@ class SheetBuilder:
|
||||
return group
|
||||
|
||||
def change_titleblock(self, sheet, titleblock_name):
|
||||
ootb_titleblock_path = os.path.join(self.data_dir, "templates", "titleblocks", titleblock_name + ".svg")
|
||||
titleblock_path = tool.Drawing.get_default_titleblock_path(titleblock_name)
|
||||
sheet_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
|
||||
sheet_dir = os.path.dirname(sheet_path)
|
||||
|
||||
os.makedirs(sheet_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(sheet_dir, "titleblocks"), exist_ok=True)
|
||||
if not os.path.exists(titleblock_path):
|
||||
shutil.copy(ootb_titleblock_path, titleblock_path)
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
ET.register_namespace("xlink", "http://www.w3.org/1999/xlink")
|
||||
|
||||
titleblock_svg_path = os.path.join(self.data_dir, "templates", "titleblocks", f"{titleblock_name}.svg")
|
||||
view_root = ET.parse(titleblock_svg_path).getroot()
|
||||
view_root = ET.parse(ootb_titleblock_path).getroot()
|
||||
view_width = self.convert_to_mm(view_root.attrib.get("width"))
|
||||
view_height = self.convert_to_mm(view_root.attrib.get("height"))
|
||||
|
||||
sheet_dir = os.path.join(self.data_dir, "sheets")
|
||||
sheet_name = os.path.splitext(os.path.basename(tool.Drawing.get_document_uri(sheet)))[0]
|
||||
sheet_path = os.path.join(sheet_dir, sheet_name + ".svg")
|
||||
sheet_tree = ET.parse(sheet_path)
|
||||
root = sheet_tree.getroot()
|
||||
|
||||
titleblock = sheet_tree.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0]
|
||||
image = titleblock.findall("{http://www.w3.org/2000/svg}image[@{http://www.w3.org/1999/xlink}href]")[0]
|
||||
image.attrib["{http://www.w3.org/1999/xlink}href"] = f"../templates/titleblocks/{titleblock_name}.svg"
|
||||
image.attrib["{http://www.w3.org/1999/xlink}href"] = os.path.relpath(titleblock_path, sheet_dir)
|
||||
image.attrib["width"] = str(view_width)
|
||||
image.attrib["height"] = str(view_height)
|
||||
|
||||
|
||||
@@ -85,13 +85,7 @@ class SvgWriter:
|
||||
self.svg.save(pretty=True)
|
||||
|
||||
def draw_underlay(self, image):
|
||||
self.svg.add(
|
||||
self.svg.image(
|
||||
os.path.join("..", "diagrams", os.path.basename(image)),
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
)
|
||||
)
|
||||
self.svg.add(self.svg.image(os.path.basename(image), width=self.width, height=self.height))
|
||||
return self
|
||||
|
||||
def setup_drawing_resource_paths(self, element):
|
||||
|
||||
@@ -84,7 +84,7 @@ class BIM_PT_camera(Panel):
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.create_drawing", text="Create Drawing", icon="OUTPUT")
|
||||
op = row.operator("bim.open_view", icon="URL", text="")
|
||||
op = row.operator("bim.open_drawing", icon="URL", text="")
|
||||
op.view = context.active_object.name.split("/")[1]
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ class BIM_PT_drawings(Panel):
|
||||
).drawing = active_drawing.ifc_definition_id
|
||||
col = row.column()
|
||||
col.alignment = "RIGHT"
|
||||
op = row.operator("bim.open_view", icon="URL", text="")
|
||||
op = row.operator("bim.open_drawing", icon="URL", text="")
|
||||
op.view = active_drawing.name
|
||||
op = row.operator("bim.activate_view", icon="OUTLINER_OB_CAMERA", text="")
|
||||
op.drawing = active_drawing.ifc_definition_id
|
||||
@@ -281,6 +281,7 @@ class BIM_PT_sheets(Panel):
|
||||
active_sheet = self.props.sheets[self.props.active_sheet_index]
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.rename_sheet", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.open_sheet", icon="URL", text="")
|
||||
row.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
||||
row.operator("bim.add_schedule_to_sheet", icon="PRESET_NEW", text="")
|
||||
@@ -510,7 +511,7 @@ class BIM_UL_sheets(bpy.types.UIList):
|
||||
layout.label(text="", translate=False)
|
||||
return
|
||||
|
||||
row = layout.row()
|
||||
row = layout.row(align=True)
|
||||
if item.is_sheet:
|
||||
if item.is_expanded:
|
||||
row.operator(
|
||||
@@ -520,8 +521,8 @@ class BIM_UL_sheets(bpy.types.UIList):
|
||||
row.operator(
|
||||
"bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
|
||||
).sheet = item.ifc_definition_id
|
||||
name = "{} - {}".format(item.identification or "X", item.name or "Unnamed")
|
||||
row.prop(item, "name", text=item.identification or "X", emboss=False)
|
||||
|
||||
row.label(text=f"{item.identification} - {item.name}")
|
||||
else:
|
||||
row.label(text="", icon="BLANK1")
|
||||
if item.reference_type == "DRAWING":
|
||||
@@ -530,6 +531,9 @@ class BIM_UL_sheets(bpy.types.UIList):
|
||||
row.label(text="", icon="LONGDISPLAY")
|
||||
elif item.reference_type == "TITLEBLOCK":
|
||||
row.label(text="", icon="MENU_PANEL")
|
||||
elif item.reference_type == "REVISION":
|
||||
row.label(text="", icon="RECOVER_LAST")
|
||||
|
||||
if item.identification:
|
||||
name = f"{item.identification} - {item.name or 'Unnamed'}"
|
||||
else:
|
||||
|
||||
@@ -516,7 +516,7 @@ class EditAssignedMaterial(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
class EnableEditingMaterialSetItemProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_material_set_item_profile"
|
||||
bl_label = "Enable Editing Material Set Item"
|
||||
bl_label = "Enable Editing Material Set Item Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
material_set_item: bpy.props.IntProperty()
|
||||
@@ -532,7 +532,7 @@ class EnableEditingMaterialSetItemProfile(bpy.types.Operator):
|
||||
|
||||
class DisableEditingMaterialSetItemProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_material_set_item_profile"
|
||||
bl_label = "Disable Editing Material Set Item"
|
||||
bl_label = "Disable Editing Material Set Item Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
|
||||
@@ -402,7 +402,7 @@ class MirrorElements(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.mirror_elements"
|
||||
bl_label = "Mirror Elements"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Faux-mirrors the selected object by an active empty along a mirror plane."
|
||||
bl_description = "Faux-mirrors the selected objects by an active empty along a mirror plane"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
@@ -68,7 +68,17 @@ class BimTool(WorkSpaceTool):
|
||||
|
||||
|
||||
def add_layout_hotkey_operator(layout, text, hotkey, description):
|
||||
op = layout.operator("bim.hotkey", text=text)
|
||||
modifiers = {
|
||||
"A": "EVENT_ALT",
|
||||
"S": "EVENT_SHIFT",
|
||||
}
|
||||
modifier, key = hotkey.split("_")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.label(text="", icon=modifiers[modifier])
|
||||
row.label(text="", icon=f"EVENT_{key}")
|
||||
|
||||
op = row.operator("bim.hotkey", text=text)
|
||||
op.hotkey = hotkey
|
||||
op.description = description
|
||||
return op
|
||||
@@ -132,10 +142,7 @@ class BimToolUI:
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.props, property="rl2", text="RL")
|
||||
elif cls.props.ifc_class in ("IfcSpaceType"):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
add_layout_hotkey_operator(row, "Generate", "S_G", bpy.ops.bim.generate_space.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Generate", "S_G", bpy.ops.bim.generate_space.__doc__)
|
||||
|
||||
@classmethod
|
||||
def draw_edit_object_interface(cls, context):
|
||||
@@ -155,45 +162,19 @@ class BimToolUI:
|
||||
op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="")
|
||||
op.x_angle = cls.props.x_angle
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Extend").hotkey = "S_E"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_T")
|
||||
row.operator("bim.hotkey", text="Butt").hotkey = "S_T"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_Y")
|
||||
row.operator("bim.hotkey", text="Mitre").hotkey = "S_Y"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_M")
|
||||
add_layout_hotkey_operator(row, "Merge", "S_M", bpy.ops.bim.merge_wall.__doc__)
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_F")
|
||||
add_layout_hotkey_operator(row, "Flip", "S_F", bpy.ops.bim.flip_wall.__doc__)
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_K")
|
||||
add_layout_hotkey_operator(row, "Split", "S_K", bpy.ops.bim.split_wall.__doc__)
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_R")
|
||||
row.operator("bim.hotkey", text="Rotate 90").hotkey = "S_R"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
add_layout_hotkey_operator(row, "Regen", "S_G", bpy.ops.bim.recalculate_wall.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Extend", "S_E", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Butt", "S_T", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Mitre", "S_Y", "")
|
||||
|
||||
add_layout_hotkey_operator(cls.layout, "Merge", "S_M", bpy.ops.bim.merge_wall.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Flip", "S_F", bpy.ops.bim.flip_wall.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Split", "S_K", bpy.ops.bim.split_wall.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Rotate 90", "S_R", bpy.ops.bim.rotate_90.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Regen", "S_G", bpy.ops.bim.recalculate_wall.__doc__)
|
||||
row.operator("bim.join_wall", icon="X", text="").join_type = ""
|
||||
|
||||
elif AuthoringData.data["active_material_usage"] == "LAYER3":
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Profile").hotkey = "S_E"
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Profile", "S_E", "")
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.props, property="x_angle", text="X Angle")
|
||||
@@ -213,36 +194,16 @@ class BimToolUI:
|
||||
op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="")
|
||||
op.depth = cls.props.extrusion_depth
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Extend").hotkey = "S_E"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_ALT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Axis").hotkey = "A_E"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_T")
|
||||
row.operator("bim.hotkey", text="Butt").hotkey = "S_T"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_Y")
|
||||
row.operator("bim.hotkey", text="Mitre").hotkey = "S_Y"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_R")
|
||||
row.operator("bim.hotkey", text="Rotate 90").hotkey = "S_R"
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
add_layout_hotkey_operator(row, "Regen", "S_G", bpy.ops.bim.recalculate_profile.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Extend", "S_E", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Axis", "A_E", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Butt", "S_T", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Mitre", "S_Y", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Rotate 90", "S_R", bpy.ops.bim.rotate_90.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Regen", "S_G", bpy.ops.bim.recalculate_profile.__doc__)
|
||||
row.operator("bim.extend_profile", icon="X", text="").join_type = ""
|
||||
|
||||
elif AuthoringData.data["active_representation_type"] == "SweptSolid":
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Profile").hotkey = "S_E"
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Profile", "S_E", "")
|
||||
|
||||
elif AuthoringData.data["active_class"] in (
|
||||
"IfcWindow",
|
||||
@@ -257,20 +218,11 @@ class BimToolUI:
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.props, property="rl1", text="RL")
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
add_layout_hotkey_operator(row, "Regen", "S_G", bpy.ops.bim.recalculate_fill.__doc__)
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_F")
|
||||
row.operator("bim.hotkey", text="Flip").hotkey = "S_F"
|
||||
add_layout_hotkey_operator(cls.layout, "Regen", "S_G", bpy.ops.bim.recalculate_fill.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Flip", "S_F", "")
|
||||
|
||||
elif AuthoringData.data["active_class"] in ("IfcSpace",):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
add_layout_hotkey_operator(row, "Regen", "S_G", bpy.ops.bim.generate_space.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Regen", "S_G", bpy.ops.bim.generate_space.__doc__)
|
||||
|
||||
elif AuthoringData.data["active_class"] in (
|
||||
"IfcCableCarrierSegmentType",
|
||||
@@ -278,39 +230,29 @@ class BimToolUI:
|
||||
"IfcDuctSegmentType",
|
||||
"IfcPipeSegmentType",
|
||||
):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="Extend", icon="EVENT_E")
|
||||
add_layout_hotkey_operator(cls.layout, "Extend", "S_E", "")
|
||||
|
||||
elif (
|
||||
(RailingData.is_loaded or not RailingData.load())
|
||||
and RailingData.data["parameters"]
|
||||
and not context.active_object.BIMRailingProperties.is_editing_path
|
||||
):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Railing Path").hotkey = "S_E"
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Railing Path", "S_E", "")
|
||||
|
||||
elif (
|
||||
(RoofData.is_loaded or not RoofData.load())
|
||||
and RoofData.data["parameters"]
|
||||
and not context.active_object.BIMRoofProperties.is_editing_path
|
||||
):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Roof Path").hotkey = "S_E"
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Roof Path", "S_E", "")
|
||||
|
||||
elif DecoratorData.get_ifc_text_data(bpy.context.object):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_E")
|
||||
row.operator("bim.hotkey", text="Edit Text").hotkey = "S_E"
|
||||
add_layout_hotkey_operator(cls.layout, "Edit Text", "S_E", "")
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_O")
|
||||
|
||||
if len(context.selected_objects) == 2:
|
||||
row.operator("bim.add_opening", text="Apply Void")
|
||||
else:
|
||||
@@ -323,27 +265,14 @@ class BimToolUI:
|
||||
else:
|
||||
row.operator("bim.show_openings", icon="HIDE_OFF", text="")
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="Align")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="Align Exterior", icon="EVENT_X")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="Align Centerline", icon="EVENT_C")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="Align Interior", icon="EVENT_V")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="Mirror", icon="EVENT_M")
|
||||
cls.layout.row(align=True).label(text="Align")
|
||||
add_layout_hotkey_operator(cls.layout, "Align Exterior", "S_X", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Align Centerline", "S_C", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Align Interior", "S_V", "")
|
||||
add_layout_hotkey_operator(cls.layout, "Mirror", "S_M", bpy.ops.bim.mirror_elements.__doc__)
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="Mode")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_ALT")
|
||||
row.label(text="", icon="EVENT_O")
|
||||
add_layout_hotkey_operator(row, "Void", "A_O", "Show / edit openings")
|
||||
cls.layout.row(align=True).label(text="Mode")
|
||||
add_layout_hotkey_operator(cls.layout, "Void", "A_O", "Show / edit openings")
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_ALT")
|
||||
row.label(text="", icon="EVENT_D")
|
||||
|
||||
@@ -74,7 +74,7 @@ class EnableEditingResource(bpy.types.Operator):
|
||||
|
||||
class DisableEditingResource(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_resource"
|
||||
bl_label = "Disable Editing Resources"
|
||||
bl_label = "Disable Editing Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
@@ -161,7 +161,7 @@ class UnassignResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
class EnableEditingResourceTime(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.enable_editing_resource_time"
|
||||
bl_label = "Enable Editing Resource Usage"
|
||||
bl_label = "Enable Editing Resource Time"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
@@ -267,7 +267,7 @@ class EditResourceCostValue(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
class EnableEditingResourceBaseQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_resource_base_quantity"
|
||||
bl_label = "Enable Editing Resource Quantity"
|
||||
bl_label = "Enable Editing Resource Base Quantity"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class EnableEditingWorkSchedule(bpy.types.Operator):
|
||||
|
||||
class EnableEditingWorkScheduleTasks(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_work_schedule_tasks"
|
||||
bl_label = "Enable Editing Tasks"
|
||||
bl_label = "Enable Editing Work Schedule Tasks"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
work_schedule: bpy.props.IntProperty()
|
||||
|
||||
@@ -961,7 +961,7 @@ class EditSequenceTimeLag(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
class DisableEditingSequence(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_sequence"
|
||||
bl_label = "Disable Editing Sequence Attributes"
|
||||
bl_label = "Disable Editing Sequence"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
@@ -1276,7 +1276,7 @@ class LoadTaskAnimationColors(bpy.types.Operator):
|
||||
|
||||
class DisableEditingTaskAnimationColors(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_task_animation_colors"
|
||||
bl_label = "Disable Editing Colors"
|
||||
bl_label = "Disable Editing Task Animation Colors"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
@@ -182,11 +182,11 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
row.prop(context.scene.BIMProperties, "data_dir")
|
||||
row.operator("bim.select_data_dir", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.DocProperties, "docs_dir")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.DocProperties, "sheets_dir")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.DocProperties, "layouts_dir")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.DocProperties, "titleblocks_dir")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.DocProperties, "drawings_dir")
|
||||
|
||||
@@ -78,7 +78,7 @@ def add_sheet(ifc, drawing, titleblock=None):
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
reference=layout,
|
||||
attributes={"Location": drawing.get_default_sheet_path(identification, "UNTITLED"), "Description": "LAYOUT"},
|
||||
attributes={"Location": drawing.get_default_layout_path(identification, "UNTITLED"), "Description": "LAYOUT"},
|
||||
)
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
@@ -94,13 +94,37 @@ def open_sheet(drawing, sheet=None):
|
||||
|
||||
|
||||
def remove_sheet(ifc, drawing, sheet=None):
|
||||
for reference in drawing.get_document_references(sheet):
|
||||
if drawing.get_reference_description(reference) in ("LAYOUT", "SHEET", "REVISION", "RASTER"):
|
||||
uri = ifc.resolve_uri(drawing.get_document_uri(reference))
|
||||
if drawing.does_file_exist(uri):
|
||||
drawing.delete_file(uri)
|
||||
ifc.run("document.remove_information", information=sheet)
|
||||
drawing.import_sheets()
|
||||
|
||||
|
||||
def update_sheet_name(ifc, drawing, sheet=None, name=None):
|
||||
if drawing.get_name(sheet) != name:
|
||||
ifc.run("document.edit_information", information=sheet, attributes={"Name": name})
|
||||
def rename_sheet(ifc, drawing, sheet=None, identification=None, name=None):
|
||||
ifc.run(
|
||||
"document.edit_information", information=sheet, attributes={"Identification": identification, "Name": name}
|
||||
)
|
||||
for reference in drawing.get_document_references(sheet):
|
||||
description = drawing.get_reference_description(reference)
|
||||
if description == "SHEET":
|
||||
old_location = drawing.get_reference_location(reference)
|
||||
new_location = drawing.get_default_sheet_path(identification, name)
|
||||
if old_location != new_location:
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": new_location})
|
||||
old_location = ifc.resolve_uri(old_location)
|
||||
if drawing.does_file_exist(old_location):
|
||||
drawing.move_file(old_location, ifc.resolve_uri(new_location))
|
||||
elif description == "LAYOUT":
|
||||
old_location = drawing.get_reference_location(reference)
|
||||
new_location = drawing.get_default_layout_path(identification, name)
|
||||
if old_location != new_location:
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": new_location})
|
||||
old_location = ifc.resolve_uri(old_location)
|
||||
if drawing.does_file_exist(old_location):
|
||||
drawing.move_file(old_location, ifc.resolve_uri(new_location))
|
||||
|
||||
|
||||
def load_schedules(drawing):
|
||||
@@ -213,6 +237,21 @@ def duplicate_drawing(ifc, drawing_tool, drawing=None, should_duplicate_annotati
|
||||
drawing_tool.copy_representation(annotation, new_annotation)
|
||||
ifc.run("group.unassign_group", group=group, product=new_annotation)
|
||||
ifc.run("group.assign_group", group=new_group, products=[new_annotation])
|
||||
|
||||
old_reference = drawing_tool.get_drawing_document(new_drawing)
|
||||
ifc.run("document.unassign_document", product=new_drawing, document=old_reference)
|
||||
|
||||
information = ifc.run("document.add_information")
|
||||
uri = drawing_tool.get_default_drawing_path(drawing_name)
|
||||
reference = ifc.run("document.add_reference", information=information)
|
||||
if ifc.get_schema() == "IFC2X3":
|
||||
attributes = {"DocumentId": "X", "Name": drawing_name, "Scope": "DRAWING"}
|
||||
else:
|
||||
attributes = {"Identification": "X", "Name": drawing_name, "Scope": "DRAWING"}
|
||||
ifc.run("document.edit_information", information=information, attributes=attributes)
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": uri})
|
||||
ifc.run("document.assign_document", product=new_drawing, document=reference)
|
||||
|
||||
drawing_tool.import_drawings()
|
||||
return new_drawing
|
||||
|
||||
@@ -230,7 +269,11 @@ def remove_drawing(ifc, drawing_tool, drawing=None):
|
||||
if reference_obj:
|
||||
drawing_tool.delete_object(reference_obj)
|
||||
ifc.run("root.remove_product", product=reference)
|
||||
ifc.run("document.remove_information", information=drawing_tool.get_drawing_document(drawing))
|
||||
information = drawing_tool.get_reference_document(drawing_tool.get_drawing_document(drawing))
|
||||
uri = ifc.resolve_uri(drawing_tool.get_document_uri(information))
|
||||
if drawing_tool.does_file_exist(uri):
|
||||
drawing_tool.delete_file(uri)
|
||||
ifc.run("document.remove_information", information=information)
|
||||
ifc.run("root.remove_product", product=drawing)
|
||||
drawing_tool.import_drawings()
|
||||
|
||||
@@ -245,6 +288,17 @@ def update_drawing_name(ifc, drawing_tool, drawing=None, name=None):
|
||||
if collection:
|
||||
drawing_tool.set_drawing_collection_name(group, collection)
|
||||
|
||||
reference = drawing_tool.get_drawing_document(drawing)
|
||||
information = drawing_tool.get_reference_document(reference)
|
||||
ifc.run("document.edit_information", information=information, attributes={"Name": name})
|
||||
old_location = drawing_tool.get_reference_location(reference)
|
||||
new_location = drawing_tool.get_default_drawing_path(name)
|
||||
if old_location != new_location:
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": new_location})
|
||||
old_location = ifc.resolve_uri(old_location)
|
||||
if drawing_tool.does_file_exist(old_location):
|
||||
drawing_tool.move_file(old_location, ifc.resolve_uri(new_location))
|
||||
|
||||
|
||||
def add_annotation(ifc, collector, drawing_tool, drawing=None, object_type=None):
|
||||
context = drawing_tool.get_annotation_context(drawing_tool.get_drawing_target_view(drawing))
|
||||
|
||||
@@ -226,20 +226,22 @@ class Document:
|
||||
@interface
|
||||
class Drawing:
|
||||
def activate_view(cls, camera): pass
|
||||
def add_literal_to_annotation(cls, obj, Literal='Literal', Path='RIGHT', BoxAlignment='bottom-left'): pass
|
||||
def copy_representation(cls, source, dest): pass
|
||||
def create_annotation_object(cls, drawing, object_type): pass
|
||||
def setup_annotation_object(cls, obj, object_type): pass
|
||||
def create_camera(cls, name, matrix): pass
|
||||
def create_svg_schedule(cls, schedule): pass
|
||||
def create_svg_sheet(cls, document, titleblock): pass
|
||||
def delete_collection(cls, collection): pass
|
||||
def delete_drawing_elements(cls, elements): pass
|
||||
def delete_file(cls, uri): pass
|
||||
def delete_object(cls, obj): pass
|
||||
def disable_editing_assigned_product(cls, obj): pass
|
||||
def disable_editing_drawings(cls): pass
|
||||
def disable_editing_schedules(cls): pass
|
||||
def disable_editing_sheets(cls): pass
|
||||
def disable_editing_text(cls, obj): pass
|
||||
def does_file_exist(cls, uri): pass
|
||||
def enable_editing(cls, obj): pass
|
||||
def enable_editing_assigned_product(cls, obj): pass
|
||||
def enable_editing_drawings(cls): pass
|
||||
@@ -257,21 +259,25 @@ class Drawing:
|
||||
def get_body_context(cls): pass
|
||||
def get_default_drawing_path(cls, name): pass
|
||||
def get_default_drawing_resource_path(cls, resource): pass
|
||||
def get_default_layout_path(cls, identification, name): pass
|
||||
def get_default_sheet_path(cls, identification, name): pass
|
||||
def get_document_uri(cls, document): pass
|
||||
def get_default_sheet_path(cls, identification, name): pass
|
||||
def get_default_titleblock_path(cls, name): pass
|
||||
def get_document_references(cls, document): pass
|
||||
def get_document_uri(cls, document, description=None): pass
|
||||
def get_drawing_collection(cls, drawing): pass
|
||||
def get_drawing_document(cls, drawing): pass
|
||||
def get_drawing_group(cls, drawing): pass
|
||||
def get_path_filename(cls, uri): pass
|
||||
def get_drawing_references(cls, drawing): pass
|
||||
def get_drawing_target_view(cls, drawing): pass
|
||||
def get_group_elements(cls, group): pass
|
||||
def get_ifc_representation_class(cls, object_type): pass
|
||||
def get_name(cls, element): pass
|
||||
def get_path_filename(cls, uri): pass
|
||||
def get_reference_description(cls, reference): pass
|
||||
def get_reference_document(cls, reference): pass
|
||||
def get_reference_location(cls, reference): pass
|
||||
def get_text_literal(cls, obj): pass
|
||||
def remove_literal_from_annotation(cls, obj, literal): pass
|
||||
def synchronise_ifc_and_text_attributes(cls, obj): pass
|
||||
def add_literal_to_annotation(cls, obj, Literal='Literal', Path='RIGHT', BoxAlignment='bottom-left'): pass
|
||||
def import_assigned_product(cls, obj): pass
|
||||
def import_drawings(cls): pass
|
||||
def import_schedules(cls): pass
|
||||
@@ -279,16 +285,20 @@ class Drawing:
|
||||
def import_text_attributes(cls, obj): pass
|
||||
def is_camera_orthographic(cls): pass
|
||||
def is_drawing_active(cls): pass
|
||||
def move_file(cls, src, dest): pass
|
||||
def open_spreadsheet(cls, uri): pass
|
||||
def open_svg(cls, filepath): pass
|
||||
def remove_literal_from_annotation(cls, obj, literal): pass
|
||||
def run_root_assign_class(cls, obj=None, ifc_class=None, predefined_type=None, should_add_representation=True, context=None, ifc_representation_class=None): pass
|
||||
def select_assigned_product(cls, drawing): pass
|
||||
def set_drawing_collection_name(cls, group, collection): pass
|
||||
def set_name(cls, element, name): pass
|
||||
def setup_annotation_object(cls, obj, object_type): pass
|
||||
def show_decorations(cls): pass
|
||||
def sync_object_placement(cls, obj): pass
|
||||
def update_text_value(cls, obj): pass
|
||||
def synchronise_ifc_and_text_attributes(cls, obj): pass
|
||||
def update_text_size_pset(cls, obj): pass
|
||||
def update_text_value(cls, obj): pass
|
||||
|
||||
|
||||
@interface
|
||||
|
||||
@@ -21,6 +21,7 @@ import re
|
||||
import bpy
|
||||
import math
|
||||
import bmesh
|
||||
import shutil
|
||||
import logging
|
||||
import mathutils
|
||||
import webbrowser
|
||||
@@ -136,7 +137,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
def create_svg_sheet(cls, document, titleblock):
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir
|
||||
uri = cls.get_document_uri(document)
|
||||
uri = cls.get_document_uri(document, "LAYOUT")
|
||||
sheet_builder.create(uri, titleblock)
|
||||
return uri
|
||||
|
||||
@@ -152,7 +153,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
if obj:
|
||||
obj_data = obj.data
|
||||
bpy.data.objects.remove(obj)
|
||||
if obj_data.users == 0: # in case we have drawing element types
|
||||
if obj_data and obj_data.users == 0: # in case we have drawing element types
|
||||
cls.remove_object_data(obj_data)
|
||||
|
||||
@classmethod
|
||||
@@ -163,7 +164,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
elif isinstance(data, bpy.types.Mesh):
|
||||
bpy.data.meshes.remove(data)
|
||||
elif isinstance(data, bpy.types.Curve):
|
||||
bpy.data.curves.remove(C.object.data)
|
||||
bpy.data.curves.remove(data)
|
||||
|
||||
@classmethod
|
||||
def delete_object(cls, obj):
|
||||
@@ -583,8 +584,9 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
continue
|
||||
|
||||
for reference in cls.get_document_references(sheet):
|
||||
if reference.Description == "LAYOUT":
|
||||
continue # The layout itself is an internal detail and should not be visible to users
|
||||
if reference.Description in ("SHEET", "LAYOUT", "RASTER"):
|
||||
# These references are an internal detail and should not be visible to users
|
||||
continue
|
||||
new = props.sheets.add()
|
||||
new.ifc_definition_id = reference.id()
|
||||
new.is_sheet = False
|
||||
@@ -726,6 +728,18 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
|
||||
# TODO below this point is highly experimental prototype code with no tests
|
||||
|
||||
@classmethod
|
||||
def does_file_exist(cls, uri):
|
||||
return os.path.exists(uri)
|
||||
|
||||
@classmethod
|
||||
def delete_file(cls, uri):
|
||||
os.remove(uri)
|
||||
|
||||
@classmethod
|
||||
def move_file(cls, src, dest):
|
||||
shutil.move(src, dest)
|
||||
|
||||
@classmethod
|
||||
def generate_drawing_name(cls, target_view, location_hint):
|
||||
if target_view in ("PLAN_VIEW", "REFLECTED_PLAN_VIEW") and location_hint:
|
||||
@@ -737,6 +751,12 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
return location_hint + " " + target_view.split("_")[0]
|
||||
return target_view
|
||||
|
||||
@classmethod
|
||||
def get_default_layout_path(cls, identification, name):
|
||||
return os.path.join(
|
||||
bpy.context.scene.DocProperties.layouts_dir, cls.sanitise_filename(f"{identification} - {name}.svg")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_default_sheet_path(cls, identification, name):
|
||||
return os.path.join(
|
||||
@@ -753,7 +773,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
|
||||
@classmethod
|
||||
def sanitise_filename(cls, name):
|
||||
return "".join(x for x in name if (x.isalnum() or x in "_- "))
|
||||
return "".join(x for x in name if (x.isalnum() or x in "._- "))
|
||||
|
||||
@classmethod
|
||||
def get_default_drawing_resource_path(cls, resource):
|
||||
@@ -1176,6 +1196,14 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
return document.DocumentReferences or []
|
||||
return document.HasDocumentReferences or []
|
||||
|
||||
@classmethod
|
||||
def get_reference_description(cls, reference):
|
||||
return reference.Description
|
||||
|
||||
@classmethod
|
||||
def get_reference_location(cls, reference):
|
||||
return reference.Location
|
||||
|
||||
@classmethod
|
||||
def get_reference_element(cls, reference):
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
@@ -1211,16 +1239,21 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
|
||||
@classmethod
|
||||
def get_drawing_elements(cls, drawing):
|
||||
"""returns a set of elements that are included in the drawing"""
|
||||
ifc_file = tool.Ifc.get()
|
||||
pset = ifcopenshell.util.element.get_psets(drawing).get("EPset_Drawing", {})
|
||||
include = pset.get("Include", None)
|
||||
if include:
|
||||
elements = set(ifcopenshell.util.selector.Selector.parse(tool.Ifc.get(), include))
|
||||
elements = set(ifcopenshell.util.selector.Selector.parse(ifc_file, include))
|
||||
else:
|
||||
elements = set(tool.Ifc.get().by_type("IfcElement"))
|
||||
elements = set(ifc_file.by_type("IfcElement"))
|
||||
annotations = tool.Drawing.get_group_elements(tool.Drawing.get_drawing_group(drawing))
|
||||
elements.update(annotations)
|
||||
|
||||
exclude = pset.get("Exclude", None)
|
||||
if exclude:
|
||||
elements -= set(ifcopenshell.util.selector.Selector.parse(tool.Ifc.get(), exclude, elements=elements))
|
||||
elements -= set(tool.Ifc.get().by_type("IfcOpeningElement"))
|
||||
elements -= set(ifcopenshell.util.selector.Selector.parse(ifc_file, exclude, elements=elements))
|
||||
elements -= set(ifc_file.by_type("IfcOpeningElement"))
|
||||
return elements
|
||||
|
||||
@classmethod
|
||||
@@ -1293,11 +1326,17 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
tool.Spatial.set_active_object(camera)
|
||||
|
||||
# sync viewport objects visibility with selectors from EPset_Drawing/Include and /Exclude
|
||||
drawing_elements = cls.get_drawing_elements(tool.Ifc.get_entity(camera))
|
||||
for element in tool.Ifc.get().by_type("IfcElement"):
|
||||
ifc_file = tool.Ifc.get()
|
||||
drawing = tool.Ifc.get_entity(camera)
|
||||
all_drawing_elements = set(ifc_file.by_type("IfcElement"))
|
||||
annotations = tool.Drawing.get_group_elements(tool.Drawing.get_drawing_group(drawing))
|
||||
all_drawing_elements.update(annotations)
|
||||
filtered_drawing_elements = cls.get_drawing_elements(drawing)
|
||||
|
||||
for element in all_drawing_elements:
|
||||
if element.is_a() in ("IfcOpeningElement",):
|
||||
continue
|
||||
|
||||
obj = tool.Ifc.get_object(element)
|
||||
obj.hide_viewport = element not in drawing_elements
|
||||
obj.hide_render = element not in drawing_elements
|
||||
obj.hide_set(element not in filtered_drawing_elements)
|
||||
obj.hide_render = element not in filtered_drawing_elements
|
||||
|
||||
@@ -8,5 +8,7 @@
|
||||
</magic>
|
||||
<generic-icon name="x-ifc"/>
|
||||
<glob pattern="*.ifc"/>
|
||||
<glob pattern="*.ifczip"/>
|
||||
<glob pattern="*.ifcxml"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
|
||||
@@ -84,14 +84,26 @@ class TestDisableEditingSheets:
|
||||
class TestAddSheet:
|
||||
def test_run(self, ifc, drawing):
|
||||
ifc.run("document.add_information").should_be_called().will_return("sheet")
|
||||
ifc.run("document.add_reference", information="sheet").should_be_called().will_return("reference")
|
||||
drawing.generate_sheet_identification().should_be_called().will_return("identification")
|
||||
drawing.ensure_unique_identification("identification").should_be_called().will_return("u_identification")
|
||||
ifc.get_schema().should_be_called().will_return("IFC4")
|
||||
drawing.get_default_sheet_path("u_identification", "UNTITLED").should_be_called().will_return("uri")
|
||||
drawing.get_default_layout_path("u_identification", "UNTITLED").should_be_called().will_return("layout_path")
|
||||
drawing.get_default_titleblock_path("titleblock").should_be_called().will_return("titleblock_path")
|
||||
ifc.run(
|
||||
"document.edit_information",
|
||||
information="sheet",
|
||||
attributes={"Identification": "u_identification", "Name": "UNTITLED", "Scope": "DOCUMENTATION", "Location": "uri"},
|
||||
attributes={"Identification": "u_identification", "Name": "UNTITLED", "Scope": "SHEET"},
|
||||
).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
reference="reference",
|
||||
attributes={"Location": "layout_path", "Description": "LAYOUT"},
|
||||
).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
reference="reference",
|
||||
attributes={"Location": "titleblock_path", "Description": "TITLEBLOCK"},
|
||||
).should_be_called()
|
||||
drawing.create_svg_sheet("sheet", "titleblock").should_be_called()
|
||||
drawing.import_sheets().should_be_called()
|
||||
@@ -99,13 +111,26 @@ class TestAddSheet:
|
||||
|
||||
def test_using_a_document_id_in_ifc2x3(self, ifc, drawing):
|
||||
ifc.run("document.add_information").should_be_called().will_return("sheet")
|
||||
ifc.run("document.add_reference", information="sheet").should_be_called().will_return("reference")
|
||||
drawing.generate_sheet_identification().should_be_called().will_return("identification")
|
||||
drawing.ensure_unique_identification("identification").should_be_called().will_return("u_identification")
|
||||
ifc.get_schema().should_be_called().will_return("IFC2X3")
|
||||
drawing.get_default_layout_path("u_identification", "UNTITLED").should_be_called().will_return("layout_path")
|
||||
drawing.get_default_titleblock_path("titleblock").should_be_called().will_return("titleblock_path")
|
||||
ifc.run(
|
||||
"document.edit_information",
|
||||
information="sheet",
|
||||
attributes={"DocumentId": "u_identification", "Name": "UNTITLED", "Scope": "DOCUMENTATION"},
|
||||
attributes={"DocumentId": "u_identification", "Name": "UNTITLED", "Scope": "SHEET"},
|
||||
).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
reference="reference",
|
||||
attributes={"Location": "layout_path", "Description": "LAYOUT"},
|
||||
).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_reference",
|
||||
reference="reference",
|
||||
attributes={"Location": "titleblock_path", "Description": "TITLEBLOCK"},
|
||||
).should_be_called()
|
||||
drawing.create_svg_sheet("sheet", "titleblock").should_be_called()
|
||||
drawing.import_sheets().should_be_called()
|
||||
@@ -114,13 +139,19 @@ class TestAddSheet:
|
||||
|
||||
class TestOpenSheet:
|
||||
def test_run(self, drawing):
|
||||
drawing.get_document_uri("sheet").should_be_called().will_return("uri")
|
||||
drawing.get_document_uri("sheet", "LAYOUT").should_be_called().will_return("uri")
|
||||
drawing.open_svg("uri").should_be_called()
|
||||
subject.open_sheet(drawing, sheet="sheet")
|
||||
|
||||
|
||||
class TestRemoveSheet:
|
||||
def test_run(self, ifc, drawing):
|
||||
drawing.get_document_references("sheet").should_be_called().will_return(["reference"])
|
||||
drawing.get_reference_description("reference").should_be_called().will_return("LAYOUT")
|
||||
drawing.get_document_uri("reference").should_be_called().will_return("relative_uri")
|
||||
ifc.resolve_uri("relative_uri").should_be_called().will_return("absolute_uri")
|
||||
drawing.does_file_exist("absolute_uri").should_be_called().will_return(True)
|
||||
drawing.delete_file("absolute_uri").should_be_called()
|
||||
ifc.run("document.remove_information", information="sheet").should_be_called()
|
||||
drawing.import_sheets().should_be_called()
|
||||
subject.remove_sheet(ifc, drawing, sheet="sheet")
|
||||
@@ -254,7 +285,11 @@ class TestAddDrawing:
|
||||
ifc.run("document.add_information").should_be_called().will_return("information")
|
||||
ifc.run("document.add_reference", information="information").should_be_called().will_return("reference")
|
||||
ifc.get_schema().should_be_called().will_return("IFC4")
|
||||
ifc.run("document.edit_information", information="information", attributes={"Identification": "X", "Name": "name", "Scope": "DRAWING"}).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_information",
|
||||
information="information",
|
||||
attributes={"Identification": "X", "Name": "name", "Scope": "DRAWING"},
|
||||
).should_be_called()
|
||||
ifc.run("document.edit_reference", reference="reference", attributes={"Location": "uri"}).should_be_called()
|
||||
ifc.run("document.assign_document", product="element", document="reference").should_be_called()
|
||||
drawing.import_drawings().should_be_called()
|
||||
@@ -280,6 +315,24 @@ class TestDuplicateDrawing:
|
||||
drawing.copy_representation("annotation", "new_annotation").should_be_called()
|
||||
ifc.run("group.unassign_group", group="group", product="new_annotation").should_be_called()
|
||||
ifc.run("group.assign_group", group="new_group", products=["new_annotation"]).should_be_called()
|
||||
|
||||
drawing.get_drawing_document("new_drawing").should_be_called().will_return("old_reference")
|
||||
ifc.run("document.unassign_document", product="new_drawing", document="old_reference").should_be_called()
|
||||
|
||||
ifc.run("document.add_information").should_be_called().will_return("information")
|
||||
ifc.run("document.add_reference", information="information").should_be_called().will_return("reference")
|
||||
ifc.get_schema().should_be_called().will_return("IFC4")
|
||||
drawing.get_default_drawing_path("unique_name").should_be_called().will_return("drawing_path")
|
||||
ifc.run(
|
||||
"document.edit_information",
|
||||
information="information",
|
||||
attributes={"Identification": "X", "Name": "unique_name", "Scope": "DRAWING"},
|
||||
).should_be_called()
|
||||
ifc.run(
|
||||
"document.edit_reference", reference="reference", attributes={"Location": "drawing_path"}
|
||||
).should_be_called()
|
||||
ifc.run("document.assign_document", product="new_drawing", document="reference").should_be_called()
|
||||
|
||||
drawing.import_drawings().should_be_called()
|
||||
subject.duplicate_drawing(ifc, drawing, drawing="drawing", should_duplicate_annotations=True)
|
||||
|
||||
@@ -296,7 +349,12 @@ class TestRemoveDrawing:
|
||||
ifc.get_object("reference").should_be_called().will_return("reference_obj")
|
||||
drawing.delete_object("reference_obj").should_be_called()
|
||||
ifc.run("root.remove_product", product="reference").should_be_called()
|
||||
drawing.get_drawing_document("drawing").should_be_called().will_return("information")
|
||||
drawing.get_drawing_document("drawing").should_be_called().will_return("reference")
|
||||
drawing.get_reference_document("reference").should_be_called().will_return("information")
|
||||
drawing.get_document_uri("information").should_be_called().will_return("relative_uri")
|
||||
ifc.resolve_uri("relative_uri").should_be_called().will_return("absolute_uri")
|
||||
drawing.does_file_exist("absolute_uri").should_be_called().will_return(True)
|
||||
drawing.delete_file("absolute_uri").should_be_called()
|
||||
ifc.run("document.remove_information", information="information").should_be_called()
|
||||
ifc.run("root.remove_product", product="drawing").should_be_called()
|
||||
drawing.import_drawings().should_be_called()
|
||||
@@ -310,6 +368,13 @@ class TestUpdateDrawingName:
|
||||
drawing.get_name("group").should_be_called().will_return("name")
|
||||
drawing.get_drawing_collection("drawing").should_be_called().will_return("collection")
|
||||
drawing.set_drawing_collection_name("group", "collection").should_be_called()
|
||||
|
||||
drawing.get_drawing_document("drawing").should_be_called().will_return("reference")
|
||||
drawing.get_reference_document("reference").should_be_called().will_return("information")
|
||||
ifc.run("document.edit_information", information="information", attributes={"Name": "name"}).should_be_called()
|
||||
drawing.get_reference_location("reference").should_be_called().will_return("location")
|
||||
drawing.get_default_drawing_path("name").should_be_called().will_return("location")
|
||||
|
||||
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
||||
|
||||
def test_run(self, ifc, drawing):
|
||||
@@ -320,6 +385,20 @@ class TestUpdateDrawingName:
|
||||
ifc.run("attribute.edit_attributes", product="group", attributes={"Name": "name"}).should_be_called()
|
||||
drawing.get_drawing_collection("drawing").should_be_called().will_return("collection")
|
||||
drawing.set_drawing_collection_name("group", "collection").should_be_called()
|
||||
|
||||
drawing.get_drawing_document("drawing").should_be_called().will_return("reference")
|
||||
drawing.get_reference_document("reference").should_be_called().will_return("information")
|
||||
ifc.run("document.edit_information", information="information", attributes={"Name": "name"}).should_be_called()
|
||||
drawing.get_reference_location("reference").should_be_called().will_return("old_location")
|
||||
drawing.get_default_drawing_path("name").should_be_called().will_return("new_location")
|
||||
ifc.run(
|
||||
"document.edit_reference", reference="reference", attributes={"Location": "new_location"}
|
||||
).should_be_called()
|
||||
ifc.resolve_uri("old_location").should_be_called().will_return("old_uri")
|
||||
drawing.does_file_exist("old_uri").should_be_called().will_return(True)
|
||||
ifc.resolve_uri("new_location").should_be_called().will_return("new_uri")
|
||||
drawing.move_file("old_uri", "new_uri").should_be_called()
|
||||
|
||||
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class TestDeleteDrawingElements(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||
collection = bpy.data.collections.new("Collection")
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
collection.objects.link(obj)
|
||||
@@ -488,7 +488,7 @@ class TestImportSheets(NewFile):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifc.createIfcDocumentInformation(Identification="Y", Name="FOOBAZ")
|
||||
document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||
document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR", Scope="SHEET")
|
||||
subject.import_sheets()
|
||||
props = bpy.context.scene.DocProperties
|
||||
assert props.sheets[0].ifc_definition_id == document.id()
|
||||
@@ -499,7 +499,7 @@ class TestImportSheets(NewFile):
|
||||
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||
tool.Ifc.set(ifc)
|
||||
ifc.createIfcDocumentInformation(DocumentId="Y", Name="FOOBAZ")
|
||||
document = ifc.createIfcDocumentInformation(DocumentId="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||
document = ifc.createIfcDocumentInformation(DocumentId="X", Name="FOOBAR", Scope="SHEET")
|
||||
subject.import_sheets()
|
||||
props = bpy.context.scene.DocProperties
|
||||
assert props.sheets[0].ifc_definition_id == document.id()
|
||||
|
||||
@@ -160,9 +160,6 @@ def create_entity(type, schema="IFC4", *args, **kwargs):
|
||||
return e
|
||||
|
||||
|
||||
gcroot = []
|
||||
|
||||
|
||||
def register_schema(schema):
|
||||
"""Registers a custom IFC schema
|
||||
|
||||
@@ -177,7 +174,8 @@ def register_schema(schema):
|
||||
ifcopenshell.register_schema(schema)
|
||||
ifcopenshell.file(schema="IFC_CUSTOM")
|
||||
"""
|
||||
gcroot.append(schema)
|
||||
schema.schema.this.disown()
|
||||
schema.disown()
|
||||
ifcopenshell_wrapper.register_schema(schema.schema)
|
||||
register_schema_attributes(schema.schema)
|
||||
|
||||
|
||||
@@ -58,4 +58,7 @@ class Usecase:
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]:
|
||||
self.file.remove(rel)
|
||||
if len(rel.RelatedObjects) == 1:
|
||||
self.file.remove(rel)
|
||||
else:
|
||||
rel.RelatedObjects = [o for o in rel.RelatedObjects if o != self.settings["product"]]
|
||||
|
||||
@@ -40,6 +40,10 @@ except ImportError as e:
|
||||
def set_derived_attribute(*args):
|
||||
raise TypeError("Unable to set derived attribute")
|
||||
|
||||
|
||||
def set_unsupported_attribute(*args):
|
||||
raise TypeError("This is an unsupported attribute type")
|
||||
|
||||
|
||||
# For every schema and its entities populate a list
|
||||
# of functions for every entity attribute (including
|
||||
@@ -79,6 +83,9 @@ def register_schema_attributes(schema):
|
||||
functions = [
|
||||
set_derived_attribute
|
||||
if mname == "setArgumentAsDerived"
|
||||
else
|
||||
set_unsupported_attribute
|
||||
if mname == "setArgumentAsUnknown"
|
||||
else getattr(ifcopenshell_wrapper.entity_instance, mname)
|
||||
for mname in fn_names
|
||||
]
|
||||
|
||||
@@ -84,7 +84,7 @@ class LateBoundSchemaInstantiator:
|
||||
for attr_name, decl_type, optional in attribute_definitions:
|
||||
attributes.append(w.attribute(attr_name, decl_type, optional))
|
||||
self.declarations[str(name)].set_attributes(attributes, is_derived)
|
||||
self.cache.append(attributes)
|
||||
self.cache.extend(attributes)
|
||||
|
||||
def inverse_attributes(self, name, inv_attrs):
|
||||
attributes = []
|
||||
@@ -100,6 +100,7 @@ class LateBoundSchemaInstantiator:
|
||||
en.attributes()[attribute_entity_index],
|
||||
)
|
||||
)
|
||||
self.cache.extend(attributes)
|
||||
self.declarations[str(name)].set_inverse_attributes(attributes)
|
||||
|
||||
def entity_subtypes(self, name, tys):
|
||||
@@ -110,6 +111,10 @@ class LateBoundSchemaInstantiator:
|
||||
override_schema_name or self.schema_name, list(self.declarations.values()), None
|
||||
)
|
||||
|
||||
def disown(self):
|
||||
for elem in self.cache + list(self.declarations.values()):
|
||||
elem.this.disown()
|
||||
|
||||
|
||||
class EarlyBoundCodeWriter:
|
||||
def __init__(self, schema_name):
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import functools
|
||||
@@ -302,7 +303,19 @@ def validate(f, logger, express_rules=False):
|
||||
ifcopenshell.ifcopenshell_wrapper.set_log_format_json()
|
||||
|
||||
filename = f
|
||||
f = ifcopenshell.open(f)
|
||||
try:
|
||||
f = ifcopenshell.open(f)
|
||||
except ifcopenshell.SchemaError as e:
|
||||
current_dir_files = {fn.lower(): fn for fn in os.listdir('.')}
|
||||
schema_name = str(e).split(' ')[-1].lower()
|
||||
exists = current_dir_files.get(schema_name + '.exp')
|
||||
if exists:
|
||||
schema = ifcopenshell.express.parse(exists)
|
||||
ifcopenshell.register_schema(schema)
|
||||
|
||||
f = ifcopenshell.open(f)
|
||||
else:
|
||||
raise e
|
||||
|
||||
log_internal_cpp_errors(filename, logger)
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
class TestAssignDocument(test.bootstrap.IFC4):
|
||||
def test_assigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
|
||||
def test_assigning_multiple_documents(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesDocument")) == 1
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
assert element.HasAssociations[0] == element.HasAssociations[0]
|
||||
@@ -0,0 +1,40 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
class TestUnassignDocument(test.bootstrap.IFC4):
|
||||
def test_unassigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert not len(self.file.by_type("IfcRelAssociatesDocument"))
|
||||
|
||||
def test_unassigning_a_document_used_by_multiple_entities(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
Reference in New Issue
Block a user