mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 09:32:37 +00:00
You can now create drawing sheets in IFC. See #1153.
This commit is contained in:
@@ -36,6 +36,7 @@ classes = (
|
|||||||
operator.CopyGrid,
|
operator.CopyGrid,
|
||||||
operator.CreateDrawing,
|
operator.CreateDrawing,
|
||||||
operator.CreateSheets,
|
operator.CreateSheets,
|
||||||
|
operator.DisableEditingSheets,
|
||||||
operator.DisableEditingText,
|
operator.DisableEditingText,
|
||||||
operator.DisableEditingTextProduct,
|
operator.DisableEditingTextProduct,
|
||||||
operator.EditText,
|
operator.EditText,
|
||||||
@@ -44,6 +45,7 @@ classes = (
|
|||||||
operator.EnableEditingText,
|
operator.EnableEditingText,
|
||||||
operator.EnableEditingTextProduct,
|
operator.EnableEditingTextProduct,
|
||||||
operator.GenerateReferences,
|
operator.GenerateReferences,
|
||||||
|
operator.LoadSheets,
|
||||||
operator.OpenSheet,
|
operator.OpenSheet,
|
||||||
operator.OpenView,
|
operator.OpenView,
|
||||||
operator.OpenViewCamera,
|
operator.OpenViewCamera,
|
||||||
@@ -67,12 +69,13 @@ classes = (
|
|||||||
prop.BIMTextProperties,
|
prop.BIMTextProperties,
|
||||||
ui.BIM_PT_camera,
|
ui.BIM_PT_camera,
|
||||||
ui.BIM_PT_drawing_underlay,
|
ui.BIM_PT_drawing_underlay,
|
||||||
|
ui.BIM_PT_annotation_utilities,
|
||||||
|
ui.BIM_PT_sheets,
|
||||||
ui.BIM_PT_drawings,
|
ui.BIM_PT_drawings,
|
||||||
ui.BIM_PT_schedules,
|
ui.BIM_PT_schedules,
|
||||||
ui.BIM_PT_sheets,
|
|
||||||
ui.BIM_PT_text,
|
ui.BIM_PT_text,
|
||||||
ui.BIM_PT_annotation_utilities,
|
|
||||||
ui.BIM_UL_drawinglist,
|
ui.BIM_UL_drawinglist,
|
||||||
|
ui.BIM_UL_sheets,
|
||||||
gizmos.UglyDotGizmo,
|
gizmos.UglyDotGizmo,
|
||||||
gizmos.DotGizmo,
|
gizmos.DotGizmo,
|
||||||
gizmos.DimensionLabelGizmo,
|
gizmos.DimensionLabelGizmo,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import blenderbim.tool as tool
|
|||||||
|
|
||||||
def refresh():
|
def refresh():
|
||||||
TextData.is_loaded = False
|
TextData.is_loaded = False
|
||||||
|
SheetsData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
class TextData:
|
class TextData:
|
||||||
@@ -54,3 +55,17 @@ class TextData:
|
|||||||
for rel in element.HasAssignments:
|
for rel in element.HasAssignments:
|
||||||
if rel.is_a("IfcRelAssignsToProduct"):
|
if rel.is_a("IfcRelAssignsToProduct"):
|
||||||
return rel.RelatingProduct.Name or "Unnamed"
|
return rel.RelatingProduct.Name or "Unnamed"
|
||||||
|
|
||||||
|
|
||||||
|
class SheetsData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {"total_sheets": cls.total_sheets()}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def total_sheets(cls):
|
||||||
|
return len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"])
|
||||||
|
|||||||
@@ -625,33 +625,24 @@ class AddAnnotation(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddSheet(bpy.types.Operator):
|
class AddSheet(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_sheet"
|
bl_idname = "bim.add_sheet"
|
||||||
bl_label = "Add Sheet"
|
bl_label = "Add Sheet"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
# TODO: check undo redo
|
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
scene = context.scene
|
core.add_sheet(tool.Ifc, tool.Drawing, titleblock=context.scene.DocProperties.titleblock)
|
||||||
new = scene.DocProperties.sheets.add()
|
|
||||||
new.name = "{} - SHEET".format(len(scene.DocProperties.sheets))
|
|
||||||
sheet_builder = sheeter.SheetBuilder()
|
|
||||||
sheet_builder.data_dir = scene.BIMProperties.data_dir
|
|
||||||
sheet_builder.create(new.name, scene.DocProperties.titleblock)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class OpenSheet(bpy.types.Operator):
|
class OpenSheet(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.open_sheet"
|
bl_idname = "bim.open_sheet"
|
||||||
bl_label = "Open Sheet"
|
bl_label = "Open Sheet"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.DocProperties
|
self.props = context.scene.DocProperties
|
||||||
open_with_user_command(
|
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
||||||
context.preferences.addons["blenderbim"].preferences.svg_command,
|
core.open_sheet(tool.Drawing, sheet=sheet)
|
||||||
os.path.join(context.scene.BIMProperties.data_dir, "sheets", props.active_sheet.name + ".svg"),
|
|
||||||
)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddDrawingToSheet(bpy.types.Operator):
|
class AddDrawingToSheet(bpy.types.Operator):
|
||||||
@@ -1420,3 +1411,21 @@ class DisableEditingTextProduct(bpy.types.Operator, Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.disable_editing_text_product(tool.Drawing, obj=context.active_object)
|
core.disable_editing_text_product(tool.Drawing, obj=context.active_object)
|
||||||
|
|
||||||
|
|
||||||
|
class LoadSheets(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.load_sheets"
|
||||||
|
bl_label = "Load Sheets"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.load_sheets(tool.Drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingSheets(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.disable_editing_sheets"
|
||||||
|
bl_label = "Disable Editing Text Product"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.disable_editing_sheets(tool.Drawing)
|
||||||
|
|||||||
@@ -152,11 +152,9 @@ def getTitleblocks(self, context):
|
|||||||
global titleblocks_enum
|
global titleblocks_enum
|
||||||
if len(titleblocks_enum) < 1:
|
if len(titleblocks_enum) < 1:
|
||||||
titleblocks_enum.clear()
|
titleblocks_enum.clear()
|
||||||
for filename in Path(os.path.join(context.scene.BIMProperties.data_dir, "templates", "titleblocks")).glob(
|
files = Path(os.path.join(context.scene.BIMProperties.data_dir, "templates", "titleblocks")).glob("*.svg")
|
||||||
"*.svg"
|
files = sorted([str(f.stem) for f in files])
|
||||||
):
|
titleblocks_enum.extend([(f, f, "") for f in files])
|
||||||
f = str(filename.stem)
|
|
||||||
titleblocks_enum.append((f, f, ""))
|
|
||||||
return titleblocks_enum
|
return titleblocks_enum
|
||||||
|
|
||||||
|
|
||||||
@@ -218,6 +216,8 @@ class Sheet(PropertyGroup):
|
|||||||
def get_name(self):
|
def get_name(self):
|
||||||
return self.get("name")
|
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", get=get_name, set=set_name)
|
||||||
drawings: CollectionProperty(name="Drawings", type=Drawing)
|
drawings: CollectionProperty(name="Drawings", type=Drawing)
|
||||||
active_drawing_index: IntProperty(name="Active Drawing Index")
|
active_drawing_index: IntProperty(name="Active Drawing Index")
|
||||||
@@ -282,6 +282,7 @@ class DocProperties(PropertyGroup):
|
|||||||
schedules: CollectionProperty(name="Schedules", type=Schedule)
|
schedules: CollectionProperty(name="Schedules", type=Schedule)
|
||||||
active_schedule_index: IntProperty(name="Active Schedule Index")
|
active_schedule_index: IntProperty(name="Active Schedule Index")
|
||||||
titleblock: EnumProperty(items=getTitleblocks, name="Titleblock", update=refreshTitleblocks)
|
titleblock: EnumProperty(items=getTitleblocks, name="Titleblock", update=refreshTitleblocks)
|
||||||
|
is_editing_sheets: BoolProperty(name="Is Editing Sheets", default=False)
|
||||||
sheets: CollectionProperty(name="Sheets", type=Sheet)
|
sheets: CollectionProperty(name="Sheets", type=Sheet)
|
||||||
active_sheet_index: IntProperty(name="Active Sheet Index")
|
active_sheet_index: IntProperty(name="Active Sheet Index")
|
||||||
ifc_files: CollectionProperty(name="IFCs", type=StrProperty)
|
ifc_files: CollectionProperty(name="IFCs", type=StrProperty)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class SheetBuilder:
|
|||||||
self.scale = "NTS"
|
self.scale = "NTS"
|
||||||
|
|
||||||
def create(self, name, titleblock_name):
|
def create(self, name, titleblock_name):
|
||||||
sheet_path = os.path.join(self.data_dir, f"{name}.svg")
|
sheet_path = os.path.join(self.data_dir, "sheets", f"{name}.svg")
|
||||||
root = ET.Element("svg")
|
root = ET.Element("svg")
|
||||||
root.attrib["xmlns"] = "http://www.w3.org/2000/svg"
|
root.attrib["xmlns"] = "http://www.w3.org/2000/svg"
|
||||||
root.attrib["xmlns:xlink"] = "http://www.w3.org/1999/xlink"
|
root.attrib["xmlns:xlink"] = "http://www.w3.org/1999/xlink"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import bpy
|
|||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.module.drawing.data import TextData
|
from blenderbim.bim.module.drawing.data import TextData, SheetsData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_camera(Panel):
|
class BIM_PT_camera(Panel):
|
||||||
@@ -149,11 +149,11 @@ class BIM_PT_drawing_underlay(Panel):
|
|||||||
|
|
||||||
|
|
||||||
class BIM_PT_drawings(Panel):
|
class BIM_PT_drawings(Panel):
|
||||||
bl_label = "SVG Drawings"
|
bl_label = "Drawings"
|
||||||
bl_idname = "BIM_PT_drawings"
|
bl_idname = "BIM_PT_drawings"
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "WINDOW"
|
bl_region_type = "UI"
|
||||||
bl_context = "output"
|
bl_category = "BIM Documentation"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@@ -182,11 +182,12 @@ class BIM_PT_drawings(Panel):
|
|||||||
|
|
||||||
|
|
||||||
class BIM_PT_schedules(Panel):
|
class BIM_PT_schedules(Panel):
|
||||||
bl_label = "ODS Schedules"
|
bl_label = "Schedules"
|
||||||
bl_idname = "BIM_PT_schedules"
|
bl_idname = "BIM_PT_schedules"
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "WINDOW"
|
bl_region_type = "UI"
|
||||||
bl_context = "output"
|
bl_category = "BIM Documentation"
|
||||||
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@@ -208,31 +209,39 @@ class BIM_PT_schedules(Panel):
|
|||||||
|
|
||||||
|
|
||||||
class BIM_PT_sheets(Panel):
|
class BIM_PT_sheets(Panel):
|
||||||
bl_label = "SVG Sheets"
|
bl_label = "Sheets"
|
||||||
bl_idname = "BIM_PT_sheets"
|
bl_idname = "BIM_PT_sheets"
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "WINDOW"
|
bl_region_type = "UI"
|
||||||
bl_context = "output"
|
bl_category = "BIM Documentation"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
if not SheetsData.is_loaded:
|
||||||
props = context.scene.DocProperties
|
SheetsData.load()
|
||||||
|
|
||||||
row = layout.row(align=True)
|
self.props = context.scene.DocProperties
|
||||||
row.prop(props, "titleblock", text="")
|
|
||||||
row.operator("bim.add_sheet")
|
|
||||||
|
|
||||||
if props.sheets:
|
if not self.props.is_editing_sheets:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=f"{SheetsData.data['total_sheets']} Sheets Found", icon="FILE")
|
||||||
|
row.operator("bim.load_sheets", text="", icon="IMPORT")
|
||||||
|
return
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "titleblock", text="")
|
||||||
|
row.operator("bim.add_sheet", text="", icon="ADD")
|
||||||
|
row.operator("bim.disable_editing_sheets", text="", icon="CANCEL")
|
||||||
|
|
||||||
|
if self.props.sheets:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.alignment = "RIGHT"
|
||||||
row.operator("bim.open_sheet", icon="URL", text="")
|
row.operator("bim.open_sheet", icon="URL", text="")
|
||||||
row.operator("bim.remove_sheet", icon="X", text="").index = props.active_sheet_index
|
row.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
||||||
|
row.operator("bim.add_schedule_to_sheet", icon="PRESET_NEW", text="")
|
||||||
|
row.operator("bim.create_sheets", icon="FILE_REFRESH", text="")
|
||||||
|
row.operator("bim.remove_sheet", icon="X", text="").index = self.props.active_sheet_index
|
||||||
|
|
||||||
layout.template_list("BIM_UL_generic", "", props, "sheets", props, "active_sheet_index")
|
self.layout.template_list("BIM_UL_sheets", "", self.props, "sheets", self.props, "active_sheet_index")
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.add_drawing_to_sheet")
|
|
||||||
row.operator("bim.add_schedule_to_sheet")
|
|
||||||
row = layout.row()
|
|
||||||
row.operator("bim.create_sheets")
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_text(Panel):
|
class BIM_PT_text(Panel):
|
||||||
@@ -289,15 +298,17 @@ class BIM_PT_text(Panel):
|
|||||||
|
|
||||||
class BIM_PT_annotation_utilities(Panel):
|
class BIM_PT_annotation_utilities(Panel):
|
||||||
bl_idname = "BIM_PT_annotation_utilities"
|
bl_idname = "BIM_PT_annotation_utilities"
|
||||||
bl_label = "Drawing"
|
bl_label = "Annotation"
|
||||||
bl_options = {"DEFAULT_CLOSED"}
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
bl_space_type = "VIEW_3D"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
bl_category = "BlenderBIM"
|
bl_category = "BIM Documentation"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
|
self.props = context.scene.DocProperties
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.operator("bim.clean_wireframes")
|
row.operator("bim.clean_wireframes")
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
@@ -345,21 +356,8 @@ class BIM_PT_annotation_utilities(Panel):
|
|||||||
op.object_type = "MISC"
|
op.object_type = "MISC"
|
||||||
op.data_type = "mesh"
|
op.data_type = "mesh"
|
||||||
|
|
||||||
props = context.scene.DocProperties
|
layout.prop(self.props, "should_draw_decorations")
|
||||||
|
layout.prop(self.props, "decorations_colour")
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.add_drawing")
|
|
||||||
row.operator("bim.refresh_drawing_list", icon="FILE_REFRESH", text="")
|
|
||||||
|
|
||||||
if props.drawings:
|
|
||||||
if props.active_drawing_index < len(props.drawings):
|
|
||||||
op = row.operator("bim.open_view", icon="URL", text="")
|
|
||||||
op.view = props.active_drawing.name
|
|
||||||
row.operator("bim.remove_drawing", icon="X", text="").index = props.active_drawing_index
|
|
||||||
layout.template_list("BIM_UL_drawinglist", "", props, "drawings", props, "active_drawing_index")
|
|
||||||
|
|
||||||
layout.prop(props, "should_draw_decorations")
|
|
||||||
layout.prop(props, "decorations_colour")
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_drawinglist(bpy.types.UIList):
|
class BIM_UL_drawinglist(bpy.types.UIList):
|
||||||
@@ -371,3 +369,13 @@ class BIM_UL_drawinglist(bpy.types.UIList):
|
|||||||
op.view_name = item.name
|
op.view_name = item.name
|
||||||
else:
|
else:
|
||||||
layout.label(text="", translate=False)
|
layout.label(text="", translate=False)
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_UL_sheets(bpy.types.UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
if item:
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.label(text=item.identification or "X")
|
||||||
|
row.label(text=item.name or "Unnamed")
|
||||||
|
else:
|
||||||
|
layout.label(text="", translate=False)
|
||||||
|
|||||||
@@ -56,3 +56,29 @@ def edit_text_product(ifc, drawing, obj=None, product=None):
|
|||||||
ifc.run("drawing.assign_product", relating_product=product, related_object=element)
|
ifc.run("drawing.assign_product", relating_product=product, related_object=element)
|
||||||
drawing.update_text_value(obj)
|
drawing.update_text_value(obj)
|
||||||
drawing.disable_editing_text_product(obj)
|
drawing.disable_editing_text_product(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def load_sheets(drawing):
|
||||||
|
drawing.import_sheets()
|
||||||
|
drawing.enable_editing_sheets()
|
||||||
|
|
||||||
|
|
||||||
|
def disable_editing_sheets(drawing):
|
||||||
|
drawing.disable_editing_sheets()
|
||||||
|
|
||||||
|
|
||||||
|
def add_sheet(ifc, drawing, titleblock=None):
|
||||||
|
sheet = ifc.run("document.add_information")
|
||||||
|
identification = drawing.generate_sheet_identification()
|
||||||
|
identification = drawing.ensure_unique_identification(identification)
|
||||||
|
attributes = {"Identification": identification, "Name": "UNTITLED", "Scope": "DOCUMENTATION"}
|
||||||
|
if ifc.get_schema() == "IFC2X3":
|
||||||
|
attributes["DocumentId"] = attributes["Identification"]
|
||||||
|
del attributes["Identification"]
|
||||||
|
ifc.run("document.edit_information", information=sheet, attributes=attributes)
|
||||||
|
drawing.create_svg_sheet(sheet, titleblock)
|
||||||
|
drawing.import_sheets()
|
||||||
|
|
||||||
|
|
||||||
|
def open_sheet(drawing, sheet=None):
|
||||||
|
drawing.open_svg(drawing.get_sheet_filename(sheet))
|
||||||
|
|||||||
@@ -135,15 +135,23 @@ class Debug:
|
|||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Drawing:
|
class Drawing:
|
||||||
|
def create_svg_sheet(cls, document, titleblock): pass
|
||||||
|
def disable_editing_sheets(cls): pass
|
||||||
def disable_editing_text(cls, obj): pass
|
def disable_editing_text(cls, obj): pass
|
||||||
def disable_editing_text_product(cls, obj): pass
|
def disable_editing_text_product(cls, obj): pass
|
||||||
|
def enable_editing_sheets(cls): pass
|
||||||
def enable_editing_text(cls, obj): pass
|
def enable_editing_text(cls, obj): pass
|
||||||
def enable_editing_text_product(cls, obj): pass
|
def enable_editing_text_product(cls, obj): pass
|
||||||
|
def ensure_unique_identification(cls, identification): pass
|
||||||
def export_text_literal_attributes(cls, obj): pass
|
def export_text_literal_attributes(cls, obj): pass
|
||||||
|
def generate_sheet_identification(cls): pass
|
||||||
|
def get_sheet_filename(cls, document): pass
|
||||||
def get_text_literal(cls, obj): pass
|
def get_text_literal(cls, obj): pass
|
||||||
def get_text_product(cls, element): pass
|
def get_text_product(cls, element): pass
|
||||||
|
def import_sheets(cls): pass
|
||||||
def import_text_attributes(cls, obj): pass
|
def import_text_attributes(cls, obj): pass
|
||||||
def import_text_product(cls, obj): pass
|
def import_text_product(cls, obj): pass
|
||||||
|
def open_svg(cls, filepath): pass
|
||||||
def update_text_value(cls, obj): pass
|
def update_text_value(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,27 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import bpy
|
import bpy
|
||||||
|
import webbrowser
|
||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
|
import blenderbim.bim.module.drawing.sheeter as sheeter
|
||||||
|
|
||||||
|
|
||||||
class Drawing(blenderbim.core.tool.Drawing):
|
class Drawing(blenderbim.core.tool.Drawing):
|
||||||
|
@classmethod
|
||||||
|
def create_svg_sheet(cls, document, titleblock):
|
||||||
|
sheet_builder = sheeter.SheetBuilder()
|
||||||
|
sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir
|
||||||
|
sheet_builder.create(cls.get_sheet_filename(document), titleblock)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def disable_editing_sheets(cls):
|
||||||
|
bpy.context.scene.DocProperties.is_editing_sheets = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def disable_editing_text(cls, obj):
|
def disable_editing_text(cls, obj):
|
||||||
obj.BIMTextProperties.is_editing = False
|
obj.BIMTextProperties.is_editing = False
|
||||||
@@ -32,6 +45,10 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def disable_editing_text_product(cls, obj):
|
def disable_editing_text_product(cls, obj):
|
||||||
obj.BIMTextProperties.is_editing_product = False
|
obj.BIMTextProperties.is_editing_product = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def enable_editing_sheets(cls):
|
||||||
|
bpy.context.scene.DocProperties.is_editing_sheets = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def enable_editing_text(cls, obj):
|
def enable_editing_text(cls, obj):
|
||||||
obj.BIMTextProperties.is_editing = True
|
obj.BIMTextProperties.is_editing = True
|
||||||
@@ -40,10 +57,36 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def enable_editing_text_product(cls, obj):
|
def enable_editing_text_product(cls, obj):
|
||||||
obj.BIMTextProperties.is_editing_product = True
|
obj.BIMTextProperties.is_editing_product = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ensure_unique_identification(cls, identification):
|
||||||
|
if tool.Ifc.get_schema() == "IFC2X3":
|
||||||
|
ids = [d.DocumentId for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"]
|
||||||
|
else:
|
||||||
|
ids = [
|
||||||
|
d.Identification for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"
|
||||||
|
]
|
||||||
|
while identification in ids:
|
||||||
|
identification += "-X"
|
||||||
|
return identification
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_text_literal_attributes(cls, obj):
|
def export_text_literal_attributes(cls, obj):
|
||||||
return blenderbim.bim.helper.export_attributes(obj.BIMTextProperties.attributes)
|
return blenderbim.bim.helper.export_attributes(obj.BIMTextProperties.attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_sheet_filename(cls, document):
|
||||||
|
if hasattr(document, "Identification"):
|
||||||
|
name = document.Identification or "X"
|
||||||
|
else:
|
||||||
|
name = document.DocumentId or "X"
|
||||||
|
name += " - " + document.Name or "Unnamed"
|
||||||
|
return name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_sheet_identification(cls):
|
||||||
|
number = len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"])
|
||||||
|
return "A" + str(number).zfill(2)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_text_literal(cls, obj):
|
def get_text_literal(cls, obj):
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
@@ -62,6 +105,19 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
if rel.is_a("IfcRelAssignsToProduct"):
|
if rel.is_a("IfcRelAssignsToProduct"):
|
||||||
return rel.RelatingProduct
|
return rel.RelatingProduct
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_sheets(cls):
|
||||||
|
bpy.context.scene.DocProperties.sheets.clear()
|
||||||
|
sheets = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"]
|
||||||
|
for sheet in sheets:
|
||||||
|
new = bpy.context.scene.DocProperties.sheets.add()
|
||||||
|
new.ifc_definition_id = sheet.id()
|
||||||
|
if tool.Ifc.get_schema() == "IFC2X3":
|
||||||
|
new.identification = sheet.DocumentId
|
||||||
|
else:
|
||||||
|
new.identification = sheet.Identification
|
||||||
|
new.name = sheet.Name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_text_attributes(cls, obj):
|
def import_text_attributes(cls, obj):
|
||||||
props = obj.BIMTextProperties
|
props = obj.BIMTextProperties
|
||||||
@@ -78,6 +134,22 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
else:
|
else:
|
||||||
obj.BIMTextProperties.relating_product = None
|
obj.BIMTextProperties.relating_product = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def open_with_user_command(cls, user_command, path):
|
||||||
|
if user_command:
|
||||||
|
commands = eval(user_command)
|
||||||
|
for command in commands:
|
||||||
|
subprocess.run(command)
|
||||||
|
else:
|
||||||
|
webbrowser.open("file://" + path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def open_svg(cls, filename):
|
||||||
|
cls.open_with_user_command(
|
||||||
|
bpy.context.preferences.addons["blenderbim"].preferences.svg_command,
|
||||||
|
os.path.join(bpy.context.scene.BIMProperties.data_dir, "sheets", filename + ".svg"),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_text_value(cls, obj):
|
def update_text_value(cls, obj):
|
||||||
element = cls.get_text_literal(obj)
|
element = cls.get_text_literal(obj)
|
||||||
|
|||||||
@@ -67,3 +67,53 @@ class TestEditTextProduct:
|
|||||||
drawing.update_text_value("obj").should_be_called()
|
drawing.update_text_value("obj").should_be_called()
|
||||||
drawing.disable_editing_text_product("obj").should_be_called()
|
drawing.disable_editing_text_product("obj").should_be_called()
|
||||||
subject.edit_text_product(ifc, drawing, obj="obj", product="product")
|
subject.edit_text_product(ifc, drawing, obj="obj", product="product")
|
||||||
|
|
||||||
|
|
||||||
|
class TestLoadSheets:
|
||||||
|
def test_run(self, drawing):
|
||||||
|
drawing.import_sheets().should_be_called()
|
||||||
|
drawing.enable_editing_sheets().should_be_called()
|
||||||
|
subject.load_sheets(drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingSheets:
|
||||||
|
def test_run(self, drawing):
|
||||||
|
drawing.disable_editing_sheets().should_be_called()
|
||||||
|
subject.disable_editing_sheets(drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddSheet:
|
||||||
|
def test_run(self, ifc, drawing):
|
||||||
|
ifc.run("document.add_information").should_be_called().will_return("sheet")
|
||||||
|
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")
|
||||||
|
ifc.run(
|
||||||
|
"document.edit_information",
|
||||||
|
information="sheet",
|
||||||
|
attributes={"Identification": "u_identification", "Name": "UNTITLED", "Scope": "DOCUMENTATION"},
|
||||||
|
).should_be_called()
|
||||||
|
drawing.create_svg_sheet("sheet", "titleblock").should_be_called()
|
||||||
|
drawing.import_sheets().should_be_called()
|
||||||
|
subject.add_sheet(ifc, drawing, titleblock="titleblock")
|
||||||
|
|
||||||
|
def test_using_a_document_id_in_ifc2x3(self, ifc, drawing):
|
||||||
|
ifc.run("document.add_information").should_be_called().will_return("sheet")
|
||||||
|
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")
|
||||||
|
ifc.run(
|
||||||
|
"document.edit_information",
|
||||||
|
information="sheet",
|
||||||
|
attributes={"DocumentId": "u_identification", "Name": "UNTITLED", "Scope": "DOCUMENTATION"},
|
||||||
|
).should_be_called()
|
||||||
|
drawing.create_svg_sheet("sheet", "titleblock").should_be_called()
|
||||||
|
drawing.import_sheets().should_be_called()
|
||||||
|
subject.add_sheet(ifc, drawing, titleblock="titleblock")
|
||||||
|
|
||||||
|
|
||||||
|
class TestOpenSheet:
|
||||||
|
def test_run(self, drawing):
|
||||||
|
drawing.get_sheet_filename("sheet").should_be_called().will_return("filename")
|
||||||
|
drawing.open_svg("filename").should_be_called()
|
||||||
|
subject.open_sheet(drawing, sheet="sheet")
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
@@ -29,6 +30,21 @@ class TestImplementsTool(NewFile):
|
|||||||
assert isinstance(subject(), blenderbim.core.tool.Drawing)
|
assert isinstance(subject(), blenderbim.core.tool.Drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateSvgSheet(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR")
|
||||||
|
subject.create_svg_sheet(document, "A1")
|
||||||
|
assert os.path.isfile(os.path.join(bpy.context.scene.BIMProperties.data_dir, "sheets", "X - FOOBAR.svg"))
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingSheets(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.DocProperties.is_editing_sheets = True
|
||||||
|
subject.disable_editing_sheets()
|
||||||
|
assert bpy.context.scene.DocProperties.is_editing_sheets == False
|
||||||
|
|
||||||
|
|
||||||
class TestDisableEditingText(NewFile):
|
class TestDisableEditingText(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
@@ -45,6 +61,13 @@ class TestDisableEditingTextProduct(NewFile):
|
|||||||
assert obj.BIMTextProperties.is_editing_product == False
|
assert obj.BIMTextProperties.is_editing_product == False
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingSheets(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.DocProperties.is_editing_sheets = False
|
||||||
|
subject.enable_editing_sheets()
|
||||||
|
assert bpy.context.scene.DocProperties.is_editing_sheets == True
|
||||||
|
|
||||||
|
|
||||||
class TestEnableEditingText(NewFile):
|
class TestEnableEditingText(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
@@ -59,6 +82,26 @@ class TestEnableEditingTextProduct(NewFile):
|
|||||||
assert obj.BIMTextProperties.is_editing_product == True
|
assert obj.BIMTextProperties.is_editing_product == True
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnsureUniqueIdentification(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR"
|
||||||
|
ifc.createIfcDocumentInformation(Identification="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR-X"
|
||||||
|
ifc.createIfcDocumentInformation(Identification="FOOBAR-X", Scope="DOCUMENTATION")
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR-X-X"
|
||||||
|
|
||||||
|
def test_unique_document_id_ifc2x3(self):
|
||||||
|
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR"
|
||||||
|
ifc.createIfcDocumentInformation(DocumentId="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR-X"
|
||||||
|
ifc.createIfcDocumentInformation(DocumentId="FOOBAR-X", Scope="DOCUMENTATION")
|
||||||
|
assert subject.ensure_unique_identification("FOOBAR") == "FOOBAR-X-X"
|
||||||
|
|
||||||
|
|
||||||
class TestExportTextLiteralAttributes(NewFile):
|
class TestExportTextLiteralAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
TestImportTextAttributes().test_run()
|
TestImportTextAttributes().test_run()
|
||||||
@@ -69,6 +112,27 @@ class TestExportTextLiteralAttributes(NewFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetSheetFilename(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
subject.get_sheet_filename(document) == "X - FOOBAR"
|
||||||
|
|
||||||
|
def test_run_ifc2x3(self):
|
||||||
|
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||||
|
document = ifc.createIfcDocumentInformation(DocumentId="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
subject.get_sheet_filename(document) == "X - FOOBAR"
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenerateSheetIdentification(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
subject.generate_sheet_identification() == "A01"
|
||||||
|
document = ifc.createIfcDocumentInformation()
|
||||||
|
subject.generate_sheet_identification() == "A02"
|
||||||
|
|
||||||
|
|
||||||
class TestGetTextLiteral(NewFile):
|
class TestGetTextLiteral(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -94,6 +158,30 @@ class TestGetTextProduct(NewFile):
|
|||||||
assert subject.get_text_product(label) == wall
|
assert subject.get_text_product(label) == wall
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportSheets(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
ifc.createIfcDocumentInformation(Identification="Y", Name="FOOBAZ")
|
||||||
|
document = ifc.createIfcDocumentInformation(Identification="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
subject.import_sheets()
|
||||||
|
props = bpy.context.scene.DocProperties
|
||||||
|
assert props.sheets[0].ifc_definition_id == document.id()
|
||||||
|
assert props.sheets[0].identification == "X"
|
||||||
|
assert props.sheets[0].name == "FOOBAR"
|
||||||
|
|
||||||
|
def test_run_ifc2x3(self):
|
||||||
|
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
ifc.createIfcDocumentInformation(DocumentId="Y", Name="FOOBAZ")
|
||||||
|
document = ifc.createIfcDocumentInformation(DocumentId="X", Name="FOOBAR", Scope="DOCUMENTATION")
|
||||||
|
subject.import_sheets()
|
||||||
|
props = bpy.context.scene.DocProperties
|
||||||
|
assert props.sheets[0].ifc_definition_id == document.id()
|
||||||
|
assert props.sheets[0].identification == "X"
|
||||||
|
assert props.sheets[0].name == "FOOBAR"
|
||||||
|
|
||||||
|
|
||||||
class TestImportTextAttributes(NewFile):
|
class TestImportTextAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -137,6 +225,11 @@ class TestImportTextProduct(NewFile):
|
|||||||
assert label_obj.BIMTextProperties.relating_product is None
|
assert label_obj.BIMTextProperties.relating_product is None
|
||||||
|
|
||||||
|
|
||||||
|
class TestOpenSvg(NewFile):
|
||||||
|
def test_nothing(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestUpdateTextValue(NewFile):
|
class TestUpdateTextValue(NewFile):
|
||||||
def test_updating_arbitrary_strings(self):
|
def test_updating_arbitrary_strings(self):
|
||||||
TestGetTextLiteral().test_run()
|
TestGetTextLiteral().test_run()
|
||||||
|
|||||||
Reference in New Issue
Block a user