Drawings list now reads data from IFC, not Blender. See #1153.

This commit is contained in:
Dion Moult
2022-01-29 17:26:09 +11:00
parent 44e4ee70ae
commit a210cf654e
12 changed files with 176 additions and 84 deletions
@@ -36,6 +36,7 @@ classes = (
operator.CopyGrid,
operator.CreateDrawing,
operator.CreateSheets,
operator.DisableEditingDrawings,
operator.DisableEditingSheets,
operator.DisableEditingText,
operator.DisableEditingTextProduct,
@@ -45,11 +46,10 @@ classes = (
operator.EnableEditingText,
operator.EnableEditingTextProduct,
operator.GenerateReferences,
operator.LoadDrawings,
operator.LoadSheets,
operator.OpenSheet,
operator.OpenView,
operator.OpenViewCamera,
operator.RefreshDrawingList,
operator.RemoveDrawing,
operator.RemoveDrawingStyle,
operator.RemoveDrawingStyleAttribute,
@@ -24,6 +24,7 @@ import blenderbim.tool as tool
def refresh():
TextData.is_loaded = False
SheetsData.is_loaded = False
DrawingsData.is_loaded = False
class TextData:
@@ -69,3 +70,17 @@ class SheetsData:
@classmethod
def total_sheets(cls):
return len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"])
class DrawingsData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"total_drawings": cls.total_drawings()}
cls.is_loaded = True
@classmethod
def total_drawings(cls):
return len([e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"])
@@ -45,6 +45,3 @@ def set_active_camera_resolution(scene):
scene.render.resolution_x = scene.camera.data.BIMCameraProperties.raster_x
scene.render.resolution_y = scene.camera.data.BIMCameraProperties.raster_y
current_drawing = scene.DocProperties.drawings[scene.DocProperties.current_drawing_index]
if scene.camera != current_drawing.camera:
scene.DocProperties.current_drawing_index = scene.DocProperties.drawings.find(scene.camera.name.split("/")[1])
bpy.ops.bim.activate_view(drawing_index=scene.DocProperties.current_drawing_index)
@@ -19,6 +19,7 @@
import bpy
import math
import mathutils.geometry
import blenderbim.tool as tool
from mathutils import Vector
# Code taken and updated from https://blenderartists.org/t/detecting-intersection-of-bounding-boxes/457520/2
@@ -263,7 +264,8 @@ def get_active_drawing(scene):
return None, None
try:
drawing = props.active_drawing
return drawing.camera.users_collection[0], drawing.camera
camera = tool.Ifc.get_object(tool.Ifc.get().by_id(drawing.ifc_definition_id))
return camera.users_collection[0], camera
except (KeyError, IndexError):
raise RuntimeError("missing drawing collection")
@@ -79,14 +79,13 @@ class AddDrawing(bpy.types.Operator):
def _execute(self, context):
self.file = IfcStore.get_file()
new = context.scene.DocProperties.drawings.add()
new.name = "DRAWING {}".format(len(context.scene.DocProperties.drawings))
drawing_name = tool.Drawing.ensure_unique_drawing_name("UNTITLED")
if not bpy.data.collections.get("Views"):
context.scene.collection.children.link(bpy.data.collections.new("Views"))
views_collection = bpy.data.collections.get("Views")
view_collection = bpy.data.collections.new("IfcGroup/" + new.name)
view_collection = bpy.data.collections.new("IfcGroup/" + drawing_name)
views_collection.children.link(view_collection)
camera = bpy.data.objects.new(new.name, bpy.data.cameras.new(new.name))
camera = bpy.data.objects.new(drawing_name, bpy.data.cameras.new(drawing_name))
camera.location = (0, 0, 1.5) # The view shall be 1.5m above the origin
camera.data.type = "ORTHO"
camera.data.ortho_scale = 50 # The default of 6m is too small
@@ -99,13 +98,12 @@ class AddDrawing(bpy.types.Operator):
view_collection.objects.link(camera)
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].region_3d.view_perspective = "CAMERA"
new.camera = camera
bpy.ops.bim.assign_class(obj=camera.name, ifc_class="IfcAnnotation", predefined_type="DRAWING")
bpy.ops.bim.activate_drawing_style()
bpy.ops.bim.add_group()
group = self.file.by_id(sorted(GroupData.groups.keys())[-1])
ifcopenshell.api.run("group.edit_group", self.file, **{"group": group, "attributes": {"Name": new.name}})
ifcopenshell.api.run("group.edit_group", self.file, **{"group": group, "attributes": {"Name": drawing_name}})
bpy.ops.bim.assign_group(product=camera.name, group=group.id())
pset = ifcopenshell.api.run(
"pset.add_pset",
@@ -125,6 +123,7 @@ class AddDrawing(bpy.types.Operator):
},
)
PsetData.load(IfcStore.get_file(), camera.BIMObjectProperties.ifc_definition_id)
tool.Drawing.import_drawings()
return {"FINISHED"}
@@ -729,40 +728,14 @@ class OpenView(bpy.types.Operator):
return {"FINISHED"}
class OpenViewCamera(bpy.types.Operator):
"""Select this drawing's camera object and expand its drawing properties"""
bl_idname = "bim.open_view_camera"
bl_label = "Open View Camera"
bl_options = {"REGISTER", "UNDO"}
view_name: bpy.props.StringProperty()
@classmethod
def poll(cls, context):
return context.mode == "OBJECT"
def execute(self, context):
doc_props = context.scene.DocProperties
doc_props.active_drawing_index = doc_props.drawings.find(self.view_name)
drawing = doc_props.active_drawing
bpy.ops.object.select_all(action="DESELECT")
drawing.camera.select_set(True)
context.view_layer.objects.active = drawing.camera
for area in context.screen.areas:
if area.ui_type == "PROPERTIES":
for space in area.spaces:
space.context = "DATA"
return {"FINISHED"}
class ActivateView(bpy.types.Operator):
bl_idname = "bim.activate_view"
bl_label = "Activate View"
bl_options = {"REGISTER", "UNDO"}
drawing_index: bpy.props.IntProperty()
drawing: bpy.props.IntProperty()
def execute(self, context):
camera = context.scene.DocProperties.drawings[self.drawing_index].camera
camera = tool.Ifc.get_object(tool.Ifc.get().by_id(self.drawing))
if not camera:
return {"FINISHED"}
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
@@ -1161,23 +1134,6 @@ class RemoveDrawingStyleAttribute(bpy.types.Operator):
return {"FINISHED"}
class RefreshDrawingList(bpy.types.Operator):
bl_idname = "bim.refresh_drawing_list"
bl_label = "Refresh Drawing List"
def execute(self, context):
doc_props = context.scene.DocProperties
doc_props.drawings.clear()
for obj in context.scene.objects:
if not isinstance(obj.data, bpy.types.Camera):
continue
if "IfcAnnotation/" in obj.name:
new = doc_props.drawings.add()
new.name = "/".join(obj.name.split("/")[1:])
new.camera = obj
return {"FINISHED"}
class CleanWireframes(bpy.types.Operator):
bl_idname = "bim.clean_wireframes"
bl_label = "Clean Wireframes"
@@ -1429,3 +1385,21 @@ class DisableEditingSheets(bpy.types.Operator, Operator):
def _execute(self, context):
core.disable_editing_sheets(tool.Drawing)
class LoadDrawings(bpy.types.Operator, Operator):
bl_idname = "bim.load_drawings"
bl_label = "Load Drawings"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
core.load_drawings(tool.Drawing)
class DisableEditingDrawings(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_drawings"
bl_label = "Disable Editing Text Product"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
core.disable_editing_drawings(tool.Drawing)
@@ -144,10 +144,6 @@ def updateDrawingName(self, context):
self.name = unique_name
def refreshActiveDrawingIndex(self, context):
bpy.ops.bim.activate_view(drawing_index=context.scene.DocProperties.active_drawing_index)
def getTitleblocks(self, context):
global titleblocks_enum
if len(titleblocks_enum) < 1:
@@ -196,6 +192,7 @@ class Variable(PropertyGroup):
class Drawing(PropertyGroup):
ifc_definition_id: IntProperty(name="IFC Definition ID")
name: StringProperty(name="Name", update=updateDrawingName)
camera: PointerProperty(name="Camera", type=bpy.types.Object)
@@ -276,8 +273,20 @@ class DocProperties(PropertyGroup):
should_use_linework_cache: BoolProperty(name="Use Linework Cache", default=False)
should_use_annotation_cache: BoolProperty(name="Use Annotation Cache", default=False)
should_extract: BoolProperty(name="Should Extract", default=True)
is_editing_drawings: BoolProperty(name="Is Editing Drawings", default=False)
target_view: EnumProperty(
items=[
("PLAN_VIEW", "Plan", ""),
("ELEVATION_VIEW", "Elevation", ""),
("SECTION_VIEW", "Section", ""),
("REFLECTED_PLAN_VIEW", "RCP", ""),
("MODEL_VIEW", "Model", ""),
],
name="Target View",
default="PLAN_VIEW",
)
drawings: CollectionProperty(name="Drawings", type=Drawing)
active_drawing_index: IntProperty(name="Active Drawing Index", update=refreshActiveDrawingIndex)
active_drawing_index: IntProperty(name="Active Drawing Index")
current_drawing_index: IntProperty(name="Current Drawing Index")
schedules: CollectionProperty(name="Schedules", type=Schedule)
active_schedule_index: IntProperty(name="Active Schedule Index")
@@ -20,7 +20,7 @@ import bpy
import blenderbim.bim.helper
import blenderbim.tool as tool
from bpy.types import Panel
from blenderbim.bim.module.drawing.data import TextData, SheetsData
from blenderbim.bim.module.drawing.data import TextData, SheetsData, DrawingsData
class BIM_PT_camera(Panel):
@@ -156,29 +156,42 @@ class BIM_PT_drawings(Panel):
bl_category = "BIM Documentation"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
props = context.scene.DocProperties
if not DrawingsData.is_loaded:
DrawingsData.load()
row = layout.row(align=True)
row.operator("bim.add_drawing")
row.operator("bim.refresh_drawing_list", icon="FILE_REFRESH", text="")
self.props = context.scene.DocProperties
if props.drawings:
if props.active_drawing_index < len(props.drawings):
if not self.props.is_editing_drawings:
row = self.layout.row(align=True)
row.label(text=f"{DrawingsData.data['total_drawings']} Drawings Found", icon="IMAGE_DATA")
row.operator("bim.load_drawings", text="", icon="IMPORT")
return
row = self.layout.row(align=True)
row.prop(self.props, "target_view", text="")
row.operator("bim.add_drawing", text="", icon="ADD")
row.operator("bim.disable_editing_drawings", text="", icon="CANCEL")
if self.props.drawings:
if self.props.active_drawing_index < len(self.props.drawings):
row = self.layout.row(align=True)
row.alignment = "RIGHT"
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")
op.view = self.props.active_drawing.name
op = row.operator("bim.activate_view", icon="OUTLINER_OB_CAMERA", text="")
op.drawing = self.props.active_drawing.ifc_definition_id
row.operator("bim.remove_drawing", icon="X", text="").index = self.props.active_drawing_index
self.layout.template_list("BIM_UL_drawinglist", "", self.props, "drawings", self.props, "active_drawing_index")
row = layout.row()
row.operator("bim.add_ifc_file")
# Commented out until federated drawing generation is rebuilt
# row = self.layout.row()
# row.operator("bim.add_ifc_file")
for index, ifc_file in enumerate(props.ifc_files):
row = layout.row(align=True)
row.prop(ifc_file, "name", text="IFC #{}".format(index + 1))
row.operator("bim.select_doc_ifc_file", icon="FILE_FOLDER", text="").index = index
row.operator("bim.remove_ifc_file", icon="X", text="").index = index
# for index, ifc_file in enumerate(self.props.ifc_files):
# row = self.layout.row(align=True)
# row.prop(ifc_file, "name", text="IFC #{}".format(index + 1))
# row.operator("bim.select_doc_ifc_file", icon="FILE_FOLDER", text="").index = index
# row.operator("bim.remove_ifc_file", icon="X", text="").index = index
class BIM_PT_schedules(Panel):
@@ -187,7 +200,6 @@ class BIM_PT_schedules(Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "BIM Documentation"
bl_options = {"DEFAULT_CLOSED"}
def draw(self, context):
layout = self.layout
@@ -365,8 +377,6 @@ class BIM_UL_drawinglist(bpy.types.UIList):
if item:
row = layout.row(align=True)
row.prop(item, "name", text="", emboss=False)
op = row.operator("bim.open_view_camera", icon="OUTLINER_OB_CAMERA", text="")
op.view_name = item.name
else:
layout.label(text="", translate=False)
@@ -87,3 +87,12 @@ def open_sheet(drawing, sheet=None):
def remove_sheet(ifc, drawing, sheet=None):
ifc.run("document.remove_document", document=sheet)
drawing.import_sheets()
def load_drawings(drawing):
drawing.import_drawings()
drawing.enable_editing_drawings()
def disable_editing_drawings(drawing):
drawing.disable_editing_drawings()
+3
View File
@@ -136,9 +136,11 @@ class Debug:
@interface
class Drawing:
def create_svg_sheet(cls, document, titleblock): pass
def disable_editing_drawings(cls): pass
def disable_editing_sheets(cls): pass
def disable_editing_text(cls, obj): pass
def disable_editing_text_product(cls, obj): pass
def enable_editing_drawings(cls): pass
def enable_editing_sheets(cls): pass
def enable_editing_text(cls, obj): pass
def enable_editing_text_product(cls, obj): pass
@@ -148,6 +150,7 @@ class Drawing:
def get_sheet_filename(cls, document): pass
def get_text_literal(cls, obj): pass
def get_text_product(cls, element): pass
def import_drawings(cls): pass
def import_sheets(cls): pass
def import_text_attributes(cls, obj): pass
def import_text_product(cls, obj): pass
+24
View File
@@ -33,6 +33,10 @@ class Drawing(blenderbim.core.tool.Drawing):
sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir
sheet_builder.create(cls.get_sheet_filename(document), titleblock)
@classmethod
def disable_editing_drawings(cls):
bpy.context.scene.DocProperties.is_editing_drawings = False
@classmethod
def disable_editing_sheets(cls):
bpy.context.scene.DocProperties.is_editing_sheets = False
@@ -45,6 +49,10 @@ class Drawing(blenderbim.core.tool.Drawing):
def disable_editing_text_product(cls, obj):
obj.BIMTextProperties.is_editing_product = False
@classmethod
def enable_editing_drawings(cls):
bpy.context.scene.DocProperties.is_editing_drawings = True
@classmethod
def enable_editing_sheets(cls):
bpy.context.scene.DocProperties.is_editing_sheets = True
@@ -57,6 +65,13 @@ class Drawing(blenderbim.core.tool.Drawing):
def enable_editing_text_product(cls, obj):
obj.BIMTextProperties.is_editing_product = True
@classmethod
def ensure_unique_drawing_name(cls, name):
names = [e.Name for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
while name in names:
name += "-X"
return name
@classmethod
def ensure_unique_identification(cls, identification):
if tool.Ifc.get_schema() == "IFC2X3":
@@ -105,6 +120,15 @@ class Drawing(blenderbim.core.tool.Drawing):
if rel.is_a("IfcRelAssignsToProduct"):
return rel.RelatingProduct
@classmethod
def import_drawings(cls):
bpy.context.scene.DocProperties.drawings.clear()
drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
for drawing in drawings:
new = bpy.context.scene.DocProperties.drawings.add()
new.ifc_definition_id = drawing.id()
new.name = drawing.Name or "Unnamed"
@classmethod
def import_sheets(cls):
bpy.context.scene.DocProperties.sheets.clear()
+13
View File
@@ -124,3 +124,16 @@ class TestRemoveSheet:
ifc.run("document.remove_document", document="sheet").should_be_called()
drawing.import_sheets().should_be_called()
subject.remove_sheet(ifc, drawing, sheet="sheet")
class TestLoadDrawings:
def test_run(self, drawing):
drawing.import_drawings().should_be_called()
drawing.enable_editing_drawings().should_be_called()
subject.load_drawings(drawing)
class TestDisableEditingDrawings:
def test_run(self, drawing):
drawing.disable_editing_drawings().should_be_called()
subject.disable_editing_drawings(drawing)
+36
View File
@@ -38,6 +38,13 @@ class TestCreateSvgSheet(NewFile):
assert os.path.isfile(os.path.join(bpy.context.scene.BIMProperties.data_dir, "sheets", "X - FOOBAR.svg"))
class TestDisableEditingDrawings(NewFile):
def test_run(self):
bpy.context.scene.DocProperties.is_editing_drawings = True
subject.disable_editing_drawings()
assert bpy.context.scene.DocProperties.is_editing_drawings == False
class TestDisableEditingSheets(NewFile):
def test_run(self):
bpy.context.scene.DocProperties.is_editing_sheets = True
@@ -61,6 +68,13 @@ class TestDisableEditingTextProduct(NewFile):
assert obj.BIMTextProperties.is_editing_product == False
class TestEnableEditingDrawings(NewFile):
def test_run(self):
bpy.context.scene.DocProperties.is_editing_drawings = False
subject.enable_editing_drawings()
assert bpy.context.scene.DocProperties.is_editing_drawings == True
class TestEnableEditingSheets(NewFile):
def test_run(self):
bpy.context.scene.DocProperties.is_editing_sheets = False
@@ -82,6 +96,17 @@ class TestEnableEditingTextProduct(NewFile):
assert obj.BIMTextProperties.is_editing_product == True
class TestEnsureUniqueDrawingName(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR"
ifc.createIfcAnnotation(Name="FOOBAR", ObjectType="DRAWING")
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X"
ifc.createIfcAnnotation(Name="FOOBAR-X", ObjectType="DRAWING")
assert subject.ensure_unique_drawing_name("FOOBAR") == "FOOBAR-X-X"
class TestEnsureUniqueIdentification(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
@@ -158,6 +183,17 @@ class TestGetTextProduct(NewFile):
assert subject.get_text_product(label) == wall
class TestImportDrawings(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
drawing = ifc.createIfcAnnotation(Name="FOOBAR", ObjectType="DRAWING")
subject.import_drawings()
props = bpy.context.scene.DocProperties
assert props.drawings[0].ifc_definition_id == drawing.id()
assert props.drawings[0].name == "FOOBAR"
class TestImportSheets(NewFile):
def test_run(self):
ifc = ifcopenshell.file()