From 074fe0d3a6e8e49e8503f9ab04e9957cbe7d7b0b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 29 Jan 2022 21:11:23 +1100 Subject: [PATCH] You can now specify a target view when creating a new drawing. See #1153. --- .../blenderbim/bim/module/drawing/operator.py | 59 ++----------------- .../blenderbim/bim/module/drawing/ui.py | 5 +- src/blenderbim/blenderbim/core/drawing.py | 15 +++++ src/blenderbim/blenderbim/core/tool.py | 4 ++ src/blenderbim/blenderbim/tool/drawing.py | 25 ++++++++ src/blenderbim/test/core/test_drawing.py | 22 ++++++- src/blenderbim/test/tool/test_drawing.py | 22 +++++++ 7 files changed, 95 insertions(+), 57 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 1dde36578e..4b2091cb82 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -65,66 +65,14 @@ class Operator: return {"FINISHED"} -class AddDrawing(bpy.types.Operator): +class AddDrawing(bpy.types.Operator, Operator): bl_idname = "bim.add_drawing" bl_label = "Add Drawing" bl_options = {"REGISTER", "UNDO"} - @classmethod - def poll(cls, context): - return IfcStore.get_file() - - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): - self.file = IfcStore.get_file() - 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/" + drawing_name) - views_collection.children.link(view_collection) - 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 - camera.data.clip_end = 10 # A slightly more reasonable default - if context.scene.unit_settings.system == "IMPERIAL": - camera.data.BIMCameraProperties.diagram_scale = '1/8"=1\'-0"|1/96' - else: - camera.data.BIMCameraProperties.diagram_scale = "1:100|1/100" - context.scene.camera = camera - 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" - 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": drawing_name}}) - bpy.ops.bim.assign_group(product=camera.name, group=group.id()) - pset = ifcopenshell.api.run( - "pset.add_pset", - self.file, - **{ - "product": self.file.by_id(camera.BIMObjectProperties.ifc_definition_id), - "name": "EPset_Drawing", - }, - ) - ifcopenshell.api.run( - "pset.edit_pset", - self.file, - **{ - "pset": pset, - "properties": {"TargetView": "PLAN_VIEW", "Scale": "1/100"}, - "pset_template": blenderbim.bim.schema.ifc.psetqto.get_by_name("EPset_Drawing"), - }, - ) - PsetData.load(IfcStore.get_file(), camera.BIMObjectProperties.ifc_definition_id) - tool.Drawing.import_drawings() - return {"FINISHED"} + self.props = context.scene.DocProperties + core.add_drawing(tool.Ifc, tool.Collector, tool.Drawing, target_view=self.props.target_view, location_hint=None) class CreateDrawing(bpy.types.Operator): @@ -143,6 +91,7 @@ class CreateDrawing(bpy.types.Operator): camera = context.scene.camera return ( IfcStore.get_file() + and camera and camera.type == "CAMERA" and camera.data.type == "ORTHO" and camera.BIMObjectProperties.ifc_definition_id diff --git a/src/blenderbim/blenderbim/bim/module/drawing/ui.py b/src/blenderbim/blenderbim/bim/module/drawing/ui.py index 33c8af1ddf..618f2c0358 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/ui.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/ui.py @@ -180,8 +180,11 @@ class BIM_PT_drawings(Panel): 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.create_drawing", text="", icon="OUTPUT") 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") + self.layout.template_list( + "BIM_UL_drawinglist", "", self.props, "drawings", self.props, "active_drawing_index" + ) # Commented out until federated drawing generation is rebuilt # row = self.layout.row() diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index 4c9789047b..7ac4654a44 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -96,3 +96,18 @@ def load_drawings(drawing): def disable_editing_drawings(drawing): drawing.disable_editing_drawings() + + +def add_drawing(ifc, collector, drawing, target_view=None, location_hint=None): + drawing_name = drawing.ensure_unique_drawing_name("UNTITLED") + drawing_matrix = drawing.generate_drawing_matrix(target_view, location_hint) + camera = drawing.create_camera(drawing_name, drawing_matrix) + # Not yet refactored + element = drawing.run_assign_class_operator(obj=camera, ifc_class="IfcAnnotation", predefined_type="DRAWING") + group = ifc.run("group.add_group") + ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name}) + ifc.run("group.assign_group", group=group, product=element) + collector.assign(camera) + pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing") + ifc.run("pset.edit_pset", pset=pset, properties={"TargetView": target_view, "Scale": "1/100"}) + drawing.import_drawings() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 71e8e63d8f..96fea3678d 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -135,6 +135,7 @@ class Debug: @interface class Drawing: + def create_camera(cls, name, matrix): pass def create_svg_sheet(cls, document, titleblock): pass def disable_editing_drawings(cls): pass def disable_editing_sheets(cls): pass @@ -144,8 +145,10 @@ class Drawing: def enable_editing_sheets(cls): pass def enable_editing_text(cls, obj): pass def enable_editing_text_product(cls, obj): pass + def ensure_unique_drawing_name(cls, name): pass def ensure_unique_identification(cls, identification): pass def export_text_literal_attributes(cls, obj): pass + def generate_drawing_matrix(cls, target_view, location_hint): pass def generate_sheet_identification(cls): pass def get_sheet_filename(cls, document): pass def get_text_literal(cls, obj): pass @@ -155,6 +158,7 @@ class Drawing: def import_text_attributes(cls, obj): pass def import_text_product(cls, obj): pass def open_svg(cls, filepath): pass + def run_assign_class_operator(cls, obj=None, ifc_class=None, predefined_type=None): pass def update_text_value(cls, obj): pass diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 2ae6c232c6..6e8729c231 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -19,6 +19,7 @@ import os import re import bpy +import mathutils import webbrowser import blenderbim.core.tool import blenderbim.tool as tool @@ -27,6 +28,21 @@ import blenderbim.bim.module.drawing.sheeter as sheeter class Drawing(blenderbim.core.tool.Drawing): + @classmethod + def create_camera(cls, name, matrix): + camera = bpy.data.objects.new(name, bpy.data.cameras.new(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 + camera.data.clip_end = 10 # A slightly more reasonable default + if bpy.context.scene.unit_settings.system == "IMPERIAL": + camera.data.BIMCameraProperties.diagram_scale = '1/8"=1\'-0"|1/96' + else: + camera.data.BIMCameraProperties.diagram_scale = "1:100|1/100" + camera.matrix_world = matrix + bpy.context.scene.collection.objects.link(camera) + return camera + @classmethod def create_svg_sheet(cls, document, titleblock): sheet_builder = sheeter.SheetBuilder() @@ -97,6 +113,10 @@ class Drawing(blenderbim.core.tool.Drawing): name += " - " + document.Name or "Unnamed" return name + @classmethod + def generate_drawing_matrix(cls, target_view, location_hint): + return mathutils.Matrix() + @classmethod def generate_sheet_identification(cls): number = len([d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"]) @@ -174,6 +194,11 @@ class Drawing(blenderbim.core.tool.Drawing): os.path.join(bpy.context.scene.BIMProperties.data_dir, "sheets", filename + ".svg"), ) + @classmethod + def run_assign_class_operator(cls, obj=None, ifc_class=None, predefined_type=None): + bpy.ops.bim.assign_class(obj=obj.name, ifc_class=ifc_class, predefined_type=predefined_type) + return tool.Ifc.get_entity(obj) + @classmethod def update_text_value(cls, obj): element = cls.get_text_literal(obj) diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index 34f7f54a3c..cfa90bd37c 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -17,7 +17,7 @@ # along with BlenderBIM Add-on. If not, see . import blenderbim.core.drawing as subject -from test.core.bootstrap import ifc, drawing +from test.core.bootstrap import ifc, drawing, collector class TestEnableEditingText: @@ -137,3 +137,23 @@ class TestDisableEditingDrawings: def test_run(self, drawing): drawing.disable_editing_drawings().should_be_called() subject.disable_editing_drawings(drawing) + + +class TestAddDrawing: + def test_run(self, ifc, collector, drawing): + drawing.ensure_unique_drawing_name("UNTITLED").should_be_called().will_return("name") + drawing.generate_drawing_matrix("target_view", "location_hint").should_be_called().will_return("matrix") + drawing.create_camera("name", "matrix").should_be_called().will_return("obj") + drawing.run_assign_class_operator( + obj="obj", ifc_class="IfcAnnotation", predefined_type="DRAWING" + ).should_be_called().will_return("element") + ifc.run("group.add_group").should_be_called().will_return("group") + ifc.run("group.edit_group", group="group", attributes={"Name": "name"}).should_be_called() + ifc.run("group.assign_group", group="group", product="element").should_be_called() + collector.assign("obj").should_be_called() + ifc.run("pset.add_pset", product="element", name="EPset_Drawing").should_be_called().will_return("pset") + ifc.run( + "pset.edit_pset", pset="pset", properties={"TargetView": "target_view", "Scale": "1/100"} + ).should_be_called() + drawing.import_drawings().should_be_called() + subject.add_drawing(ifc, collector, drawing, target_view="target_view", location_hint="location_hint") diff --git a/src/blenderbim/test/tool/test_drawing.py b/src/blenderbim/test/tool/test_drawing.py index c54d4ac42d..5e64dfb5e2 100644 --- a/src/blenderbim/test/tool/test_drawing.py +++ b/src/blenderbim/test/tool/test_drawing.py @@ -18,6 +18,7 @@ import os import bpy +import mathutils import ifcopenshell import blenderbim.core.tool import blenderbim.tool as tool @@ -30,6 +31,17 @@ class TestImplementsTool(NewFile): assert isinstance(subject(), blenderbim.core.tool.Drawing) +class TestCreateCamera(NewFile): + def test_run(self): + obj = subject.create_camera("Name", mathutils.Matrix()) + assert obj.name == "Name" + assert obj.matrix_world == mathutils.Matrix() + assert obj.data.type == "ORTHO" + assert obj.data.ortho_scale == 50 + assert obj.data.clip_end == 10 + assert obj.users_collection[0] == bpy.context.scene.collection + + class TestCreateSvgSheet(NewFile): def test_run(self): ifc = ifcopenshell.file() @@ -149,6 +161,11 @@ class TestGetSheetFilename(NewFile): subject.get_sheet_filename(document) == "X - FOOBAR" +class TestGenerateDrawingMatrix(NewFile): + def test_returning_the_origin_as_a_fallback(self): + assert subject.generate_drawing_matrix("PLAN_VIEW", None) == mathutils.Matrix() + + class TestGenerateSheetIdentification(NewFile): def test_run(self): ifc = ifcopenshell.file() @@ -266,6 +283,11 @@ class TestOpenSvg(NewFile): pass +class TestRunAssignClassOperator(NewFile): + def test_nothing(self): + pass + + class TestUpdateTextValue(NewFile): def test_updating_arbitrary_strings(self): TestGetTextLiteral().test_run()