From 132ec473ec6de3d1b240976a703a872b2a10b50e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 20 Sep 2021 17:06:02 +1000 Subject: [PATCH] New feature to see the current frame's real life date as text during a generated animation --- src/blenderbim/blenderbim/bim/import_ifc.py | 4 +- .../blenderbim/bim/module/debug/operator.py | 8 +++- .../blenderbim/bim/module/project/prop.py | 3 +- .../blenderbim/bim/module/project/ui.py | 6 +-- .../bim/module/sequence/__init__.py | 3 ++ .../bim/module/sequence/operator.py | 32 ++++++++++++++- .../blenderbim/bim/module/sequence/prop.py | 21 ++++++---- src/blenderbim/blenderbim/bim/operator.py | 2 +- src/blenderbim/test/bim/bootstrap.py | 14 ++++++- .../test/bim/module/bimtester/__init__.py | 17 ++++++++ .../test/bim/module/patch/__init__.py | 17 ++++++++ .../test/bim/module/root/__init__.py | 17 ++++++++ .../test/bim/module/sequence/__init__.py | 17 ++++++++ .../test/bim/module/sequence/test_operator.py | 39 +++++++++++++++++++ .../test/bim/module/void/__init__.py | 17 ++++++++ src/blenderbim/test/files/sample-ids.xml | 19 +++++++++ 16 files changed, 219 insertions(+), 17 deletions(-) create mode 100644 src/blenderbim/test/bim/module/sequence/__init__.py create mode 100644 src/blenderbim/test/bim/module/sequence/test_operator.py diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index f857df0486..36aa09845f 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -1312,7 +1312,9 @@ class IfcImporter: if "TargetView" in pset: camera.BIMCameraProperties.target_view = pset["TargetView"] if "Scale" in pset: - valid_scales = [i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1]] + valid_scales = [ + i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1] + ] if valid_scales: camera.BIMCameraProperties.diagram_scale = valid_scales[0] else: diff --git a/src/blenderbim/blenderbim/bim/module/debug/operator.py b/src/blenderbim/blenderbim/bim/module/debug/operator.py index 6f00f72aea..203371d748 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/operator.py +++ b/src/blenderbim/blenderbim/bim/module/debug/operator.py @@ -116,7 +116,13 @@ class CreateAllShapes(bpy.types.Operator): start = time.time() try: shape = ifcopenshell.geom.create_shape(settings, element) - print("Success", time.time()-start, len(shape.geometry.verts), len(shape.geometry.edges), len(shape.geometry.faces)) + print( + "Success", + time.time() - start, + len(shape.geometry.verts), + len(shape.geometry.edges), + len(shape.geometry.faces), + ) except: failures.append(element) print("***** FAILURE *****") diff --git a/src/blenderbim/blenderbim/bim/module/project/prop.py b/src/blenderbim/blenderbim/bim/module/project/prop.py index ed8b712939..aaff522274 100644 --- a/src/blenderbim/blenderbim/bim/module/project/prop.py +++ b/src/blenderbim/blenderbim/bim/module/project/prop.py @@ -102,7 +102,7 @@ class BIMProjectProperties(PropertyGroup): ("BLACKLIST", "Blacklist", "Filter objects using a custom blacklist query"), ], name="Filter Mode", - update=update_filter_mode + update=update_filter_mode, ) filter_categories: CollectionProperty(name="Filter Categories", type=FilterCategory) active_filter_category_index: IntProperty(name="Active Filter Category Index") @@ -119,6 +119,5 @@ class BIMProjectProperties(PropertyGroup): links: CollectionProperty(name="Links", type=Link) active_link_index: IntProperty(name="Active Link Index") - def get_library_element_index(self, lib_element): return next((i for i in range(len(self.library_elements)) if self.library_elements[i] == lib_element)) diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index b1b0c72d91..a594ad5306 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -271,9 +271,9 @@ class BIM_UL_links(UIList): row.label(text=item.name) if item.is_loaded: op = row.operator("bim.unload_link", text="", icon="UNLINKED") - op.filepath=item.name + op.filepath = item.name else: op = row.operator("bim.load_link", text="", icon="LINKED") - op.filepath=item.name + op.filepath = item.name op = row.operator("bim.unlink_ifc", text="", icon="X") - op.filepath=item.name + op.filepath = item.name diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 38c4c7cc32..12be9e5872 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -109,6 +109,7 @@ classes = ( prop.RecurrenceComponent, prop.BIMWorkCalendarProperties, prop.DatePickerProperties, + prop.BIMDateTextProperties, ui.BIM_PT_work_plans, ui.BIM_PT_work_schedules, ui.BIM_PT_work_calendars, @@ -132,6 +133,7 @@ def register(): bpy.types.Scene.BIMTaskTreeProperties = bpy.props.PointerProperty(type=prop.BIMTaskTreeProperties) bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties) bpy.types.Scene.DatePickerProperties = bpy.props.PointerProperty(type=prop.DatePickerProperties) + bpy.types.TextCurve.BIMDateTextProperties = bpy.props.PointerProperty(type=prop.BIMDateTextProperties) bpy.types.TOPBAR_MT_file_import.append(menu_func_import) @@ -141,4 +143,5 @@ def unregister(): del bpy.types.Scene.BIMTaskTreeProperties del bpy.types.Scene.BIMWorkCalendarProperties del bpy.types.Scene.DatePickerProperties + del bpy.types.TextCurve.BIMDateTextProperties bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 9179483859..afdbfdec1f 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -1742,11 +1742,12 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): self.animate_input(obj, product_frame) elif product_frame["relationship"] == "output": self.animate_output(obj, product_frame) + self.add_text_animation_handler() area = next(area for area in context.screen.areas if area.type == "VIEW_3D") area.spaces[0].shading.color_type = "OBJECT" context.scene.frame_start = self.start_frame - context.scene.frame_end = self.start_frame + self.total_frames + context.scene.frame_end = int(self.start_frame + self.total_frames) # with open("/home/dion/animation.json", "w") as json_file: # guid_frames = {} # for k, v in self.product_frames.items(): @@ -1754,6 +1755,35 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): # json.dump(guid_frames, json_file) return {"FINISHED"} + def add_text_animation_handler(self): + data = bpy.data.curves.get("Timeline") + if not data: + data = bpy.data.curves.new(type="FONT", name="Timeline") + obj = bpy.data.objects.get("Timeline") + if not obj: + obj = bpy.data.objects.new(name="Timeline", object_data=data) + bpy.context.scene.collection.objects.link(obj) + obj.data.BIMDateTextProperties.start_frame = self.start_frame + obj.data.BIMDateTextProperties.total_frames = int(self.total_frames) + obj.data.BIMDateTextProperties.start = self.props.visualisation_start + obj.data.BIMDateTextProperties.finish = self.props.visualisation_finish + bpy.app.handlers.frame_change_post.append(self.animate_text) + + def remove_text_animation_handler(self): + bpy.app.handlers.frame_change_post.remove(self.animate_text) + + def animate_text(self, scene, context): + data = bpy.data.curves.get("Timeline") + if not data or not bpy.data.objects.get("Timeline"): + self.remove_text_animation_handler() + scene.frame_current + props = data.BIMDateTextProperties + start = parser.parse(props.start, dayfirst=True, fuzzy=True) + finish = parser.parse(props.finish, dayfirst=True, fuzzy=True) + duration = finish - start + frame_date = (((scene.frame_current - props.start_frame) / props.total_frames) * duration) + start + data.body = frame_date.date().isoformat() + def animate_input(self, obj, product_frame): if product_frame["type"] in ["LOGISTIC", "MOVE", "DISPOSAL"]: self.animate_movement_from(obj, product_frame) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index b4185a1388..7f002e8197 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -204,15 +204,15 @@ def updateTaskDuration(self, context): bpy.ops.bim.load_task_properties() -def updateVisualisationStart(self, context): - updateVisualisationStartFinish(self, context, "visualisation_start") +def update_visualisation_start(self, context): + update_visualisation_start_finish(self, context, "visualisation_start") -def updateVisualisationFinish(self, context): - updateVisualisationStartFinish(self, context, "visualisation_finish") +def update_visualisation_finish(self, context): + update_visualisation_start_finish(self, context, "visualisation_finish") -def updateVisualisationStartFinish(self, context, startfinish): +def update_visualisation_start_finish(self, context, startfinish): def canonicalise_time(time): if not time: return "-" @@ -316,8 +316,8 @@ class BIMWorkScheduleProperties(PropertyGroup): active_sequence_id: IntProperty(name="Active Sequence Id") sequence_attributes: CollectionProperty(name="Sequence Attributes", type=Attribute) time_lag_attributes: CollectionProperty(name="Time Lag Attributes", type=Attribute) - visualisation_start: StringProperty(name="Visualisation Start", update=updateVisualisationStart) - visualisation_finish: StringProperty(name="Visualisation Finish", update=updateVisualisationFinish) + visualisation_start: StringProperty(name="Visualisation Start", update=update_visualisation_start) + visualisation_finish: StringProperty(name="Visualisation Finish", update=update_visualisation_finish) speed_multiplier: FloatProperty(name="Speed Multiplier", default=10000) speed_animation_duration: StringProperty(name="Speed Animation Duration", default="PT1S") speed_animation_frames: IntProperty(name="Speed Animation Frames", default=24) @@ -388,3 +388,10 @@ class BIMWorkCalendarProperties(PropertyGroup): class DatePickerProperties(PropertyGroup): display_date: StringProperty() selected_date: StringProperty() + + +class BIMDateTextProperties(PropertyGroup): + start_frame: IntProperty(name="Start Frame") + total_frames: IntProperty(name="Total Frames") + start: StringProperty(name="Start") + finish: StringProperty(name="Finish") diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index e906d01e40..1df58dba4f 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -104,7 +104,7 @@ class ImportIFC(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - bpy.ops.bim.load_project('INVOKE_DEFAULT') + bpy.ops.bim.load_project("INVOKE_DEFAULT") return {"FINISHED"} diff --git a/src/blenderbim/test/bim/bootstrap.py b/src/blenderbim/test/bim/bootstrap.py index 5b80d74633..db185504eb 100644 --- a/src/blenderbim/test/bim/bootstrap.py +++ b/src/blenderbim/test/bim/bootstrap.py @@ -78,6 +78,10 @@ def additionally_the_object_name_is_selected(name): obj.select_set(True) +def i_am_on_frame_number(number): + bpy.context.scene.frame_set(int(number)) + + def i_set_prop_to_value(prop, value): try: eval(f"bpy.context.{prop}") @@ -159,6 +163,10 @@ def the_object_name_is_not_in_the_collection_collection(name, collection): assert collection not in [c.name for c in the_object_name_exists(name).users_collection] +def the_object_name_has_a_body_of_value(name, value): + assert the_object_name_exists(name).data.body == value + + def the_collection_name1_is_in_the_collection_name2(name1, name2): assert bpy.data.collections.get(name2).children.get(name1) @@ -256,7 +264,9 @@ def the_object_name_has_number_vertices(name, number): def the_object_name_is_at_location(name, location): obj_location = the_object_name_exists(name).location - assert (obj_location - Vector([float(co) for co in location.split(",")])).length < 0.1, f"Object is at {obj_location}" + assert ( + obj_location - Vector([float(co) for co in location.split(",")]) + ).length < 0.1, f"Object is at {obj_location}" definitions = { @@ -265,6 +275,7 @@ definitions = { 'I add a cube of size "([0-9]+)" at "(.*)"': i_add_a_cube_of_size_size_at_location, 'the object "(.*)" is selected': the_object_name_is_selected, 'additionally the object "(.*)" is selected': additionally_the_object_name_is_selected, + 'I am on frame "([0-9]+)"': i_am_on_frame_number, 'I set "(.*)" to "(.*)"': i_set_prop_to_value, '"(.*)" is "(.*)"': prop_is_value, 'I enable "(.*)"': i_enable_prop, @@ -275,6 +286,7 @@ definitions = { 'the object "(.*)" is not an IFC element': the_object_name_is_not_an_ifc_element, 'the object "(.*)" is in the collection "(.*)"': the_object_name_is_in_the_collection_collection, 'the object "(.*)" is not in the collection "(.*)"': the_object_name_is_not_in_the_collection_collection, + 'the object "(.*)" has a body of "(.*)"': the_object_name_has_a_body_of_value, 'the collection "(.*)" is in the collection "(.*)"': the_collection_name1_is_in_the_collection_name2, 'the collection "(.*)" is not in the collection "(.*)"': the_collection_name1_is_not_in_the_collection_name2, "an IFC file exists": an_ifc_file_exists, diff --git a/src/blenderbim/test/bim/module/bimtester/__init__.py b/src/blenderbim/test/bim/module/bimtester/__init__.py index e69de29bb2..fb33323db9 100644 --- a/src/blenderbim/test/bim/module/bimtester/__init__.py +++ b/src/blenderbim/test/bim/module/bimtester/__init__.py @@ -0,0 +1,17 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . diff --git a/src/blenderbim/test/bim/module/patch/__init__.py b/src/blenderbim/test/bim/module/patch/__init__.py index e69de29bb2..fb33323db9 100644 --- a/src/blenderbim/test/bim/module/patch/__init__.py +++ b/src/blenderbim/test/bim/module/patch/__init__.py @@ -0,0 +1,17 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . diff --git a/src/blenderbim/test/bim/module/root/__init__.py b/src/blenderbim/test/bim/module/root/__init__.py index e69de29bb2..fb33323db9 100644 --- a/src/blenderbim/test/bim/module/root/__init__.py +++ b/src/blenderbim/test/bim/module/root/__init__.py @@ -0,0 +1,17 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . diff --git a/src/blenderbim/test/bim/module/sequence/__init__.py b/src/blenderbim/test/bim/module/sequence/__init__.py new file mode 100644 index 0000000000..fb33323db9 --- /dev/null +++ b/src/blenderbim/test/bim/module/sequence/__init__.py @@ -0,0 +1,17 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . diff --git a/src/blenderbim/test/bim/module/sequence/test_operator.py b/src/blenderbim/test/bim/module/sequence/test_operator.py new file mode 100644 index 0000000000..a37b3b5425 --- /dev/null +++ b/src/blenderbim/test/bim/module/sequence/test_operator.py @@ -0,0 +1,39 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import test.bim.bootstrap + + +class TestVisualiseWorkScheduleDateRange(test.bim.bootstrap.NewFile): + @test.bim.bootstrap.scenario + def test_seeing_the_current_frame_date_as_text(self): + return """ + Given an empty IFC project + And I press "bim.add_work_schedule" + And I press "bim.enable_editing_tasks(work_schedule=72)" + And I set "scene.BIMWorkScheduleProperties.visualisation_start" to "01/01/21" + And I set "scene.BIMWorkScheduleProperties.visualisation_finish" to "01/02/21" + And I set "scene.BIMWorkScheduleProperties.speed_types" to "FRAME_SPEED" + And I set "scene.BIMWorkScheduleProperties.speed_animation_frames" to "7" + And I set "scene.BIMWorkScheduleProperties.speed_real_duration" to "P1W" + And I press "bim.visualise_work_schedule_date_range(work_schedule=72)" + When I am on frame "1" + Then the object "Timeline" has a body of "2021-01-01" + When I am on frame "2" + Then the object "Timeline" has a body of "2021-01-02" + """ diff --git a/src/blenderbim/test/bim/module/void/__init__.py b/src/blenderbim/test/bim/module/void/__init__.py index e69de29bb2..fb33323db9 100644 --- a/src/blenderbim/test/bim/module/void/__init__.py +++ b/src/blenderbim/test/bim/module/void/__init__.py @@ -0,0 +1,17 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . diff --git a/src/blenderbim/test/files/sample-ids.xml b/src/blenderbim/test/files/sample-ids.xml index 95592edaa9..4b7ee8c15c 100644 --- a/src/blenderbim/test/files/sample-ids.xml +++ b/src/blenderbim/test/files/sample-ids.xml @@ -1,4 +1,23 @@ +