From d4eb56e360a05b22ad5b83f5558aeccf403588f9 Mon Sep 17 00:00:00 2001 From: Sigma Dimensions <79010126+myoualid@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:22:40 +0100 Subject: [PATCH] New Search and Spatial selection Tools + refactor sequence modules --- .../bim/module/sequence/operator.py | 23 +++++--- src/blenderbim/blenderbim/core/search.py | 10 ++++ src/blenderbim/blenderbim/core/sequence.py | 38 +++++--------- src/blenderbim/blenderbim/core/spatial.py | 5 +- src/blenderbim/blenderbim/core/tool.py | 18 +++++-- src/blenderbim/blenderbim/tool/__init__.py | 1 + src/blenderbim/blenderbim/tool/resource.py | 16 +++--- src/blenderbim/blenderbim/tool/search.py | 11 ++++ src/blenderbim/blenderbim/tool/sequence.py | 8 --- src/blenderbim/blenderbim/tool/spatial.py | 52 +++++++++++++++++++ 10 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 src/blenderbim/blenderbim/core/search.py create mode 100644 src/blenderbim/blenderbim/tool/search.py diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 68034f6e95..d15b7a6972 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -368,11 +368,12 @@ class AssignProduct(bpy.types.Operator, tool.Ifc.Operator): core.assign_products( tool.Ifc, tool.Sequence, + tool.Spatial, task=tool.Ifc.get().by_id(self.task), products=[tool.Ifc.get().by_id(self.relating_product)], ) else: - core.assign_products(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.assign_products(tool.Ifc, tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) class UnassignProduct(bpy.types.Operator, tool.Ifc.Operator): @@ -387,11 +388,12 @@ class UnassignProduct(bpy.types.Operator, tool.Ifc.Operator): core.unassign_products( tool.Ifc, tool.Sequence, + tool.Spatial, task=tool.Ifc.get().by_id(self.task), products=[tool.Ifc.get().by_id(self.relating_product)], ) else: - core.unassign_products(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.unassign_products(tool.Ifc, tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) class AssignProcess(bpy.types.Operator, tool.Ifc.Operator): @@ -410,11 +412,12 @@ class AssignProcess(bpy.types.Operator, tool.Ifc.Operator): core.assign_input_products( tool.Ifc, tool.Sequence, + tool.Spatial, task=tool.Ifc.get().by_id(self.task), products=[tool.Ifc.get().by_id(self.related_object)], ) else: - core.assign_input_products(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.assign_input_products(tool.Ifc, tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) elif self.related_object_type == "CONTROL": pass # TODO @@ -445,11 +448,17 @@ class UnassignProcess(bpy.types.Operator): core.unassign_input_products( tool.Ifc, tool.Sequence, + tool.Spatial, task=tool.Ifc.get().by_id(self.task), products=[tool.Ifc.get().by_id(self.related_object)], ) else: - core.unassign_input_products(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.unassign_input_products( + tool.Ifc, + tool.Sequence, + tool.Spatial, + task=tool.Ifc.get().by_id(self.task) + ) elif self.related_object_type == "CONTROL": pass # TODO return {"FINISHED"} @@ -945,7 +954,7 @@ class SelectTaskRelatedProducts(bpy.types.Operator, tool.Ifc.Operator): task: bpy.props.IntProperty() def _execute(self, context): - core.select_task_outputs(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.select_task_outputs(tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) class SelectTaskRelatedInputs(bpy.types.Operator, tool.Ifc.Operator): @@ -955,7 +964,7 @@ class SelectTaskRelatedInputs(bpy.types.Operator, tool.Ifc.Operator): task: bpy.props.IntProperty() def _execute(self, context): - core.select_task_inputs(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + core.select_task_inputs(tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) class VisualiseWorkScheduleDate(bpy.types.Operator): @@ -1204,7 +1213,7 @@ class HighlightProductRelatedTask(bpy.types.Operator, tool.Ifc.Operator): product_type: bpy.props.StringProperty() def _execute(self, context): - core.highlight_product_related_task(tool.Sequence, product_type=self.product_type) + core.highlight_product_related_task(tool.Sequence, tool.Spatial, product_type=self.product_type) class ExpandAllTasks(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/blenderbim/blenderbim/core/search.py b/src/blenderbim/blenderbim/core/search.py new file mode 100644 index 0000000000..419e18f5ef --- /dev/null +++ b/src/blenderbim/blenderbim/core/search.py @@ -0,0 +1,10 @@ +def show_all_ifc_elements(spatial): + spatial.show_scene_objects() + +def search(search, spatial, query, action): + products = search.from_selector_query(query) + spatial.deselect_objects() + try: + spatial.filter_products(products, action) + except: + return "One or More Products could not be found because they are hidden in the ViewLayer" \ No newline at end of file diff --git a/src/blenderbim/blenderbim/core/sequence.py b/src/blenderbim/blenderbim/core/sequence.py index e9287f710b..d0c48c403f 100644 --- a/src/blenderbim/blenderbim/core/sequence.py +++ b/src/blenderbim/blenderbim/core/sequence.py @@ -207,37 +207,29 @@ def unassign_successor(ifc, sequence, task=None): sequence.load_task_properties() -def assign_products(ifc, sequence, task=None, products=None): - if not products: - products = sequence.get_selected_products() - for product in products: +def assign_products(ifc, sequence, spatial, task=None, products=None): + for product in products or spatial.get_selected_products() or []: ifc.run("sequence.assign_product", relating_product=product, related_object=task) outputs = sequence.get_task_outputs(task) sequence.load_task_outputs(outputs) -def unassign_products(ifc, sequence, task=None, products=None): - if not products: - products = sequence.get_selected_products() - for product in products: +def unassign_products(ifc, sequence, spatial, task=None, products=None): + for product in products or spatial.get_selected_products() or []: ifc.run("sequence.unassign_product", relating_product=product, related_object=task) outputs = sequence.get_task_outputs(task) sequence.load_task_outputs(outputs) -def assign_input_products(ifc, sequence, task=None, products=None): - if not products: - products = sequence.get_selected_products() - for product in products: +def assign_input_products(ifc, sequence, spatial, task=None, products=None): + for product in products or spatial.get_selected_products() or []: ifc.run("sequence.assign_process", relating_process=task, related_object=product) inputs = sequence.get_task_inputs(task) sequence.load_task_inputs(inputs) -def unassign_input_products(ifc, sequence, task=None, products=None): - if not products: - products = sequence.get_selected_products() - for product in products: +def unassign_input_products(ifc, sequence, spatial, task=None, products=None): + for product in products or spatial.get_selected_products() or []: ifc.run("sequence.unassign_process", relating_process=task, related_object=product) inputs = sequence.get_task_inputs(task) sequence.load_task_inputs(inputs) @@ -423,14 +415,12 @@ def disable_editing_rel_sequence(sequence): sequence.disable_editing_rel_sequence() -def select_task_outputs(ifc, sequence, task=None): - outputs = sequence.get_task_outputs(task) - sequence.select_products(outputs) +def select_task_outputs(spatial, sequence, task=None): + spatial.select_products(products=sequence.get_task_outputs(task)) -def select_task_inputs(ifc, sequence, task=None): - inputs = sequence.get_task_inputs(task) - sequence.select_products(inputs) +def select_task_inputs(spatial, sequence, task=None): + spatial.select_products(products=sequence.get_task_inputs(task)) def recalculate_schedule(ifc, work_schedule=None): @@ -457,8 +447,8 @@ def calculate_task_duration(ifc, sequence, task=None): sequence.load_task_properties() -def highlight_product_related_task(sequence, product_type=None): - products = sequence.get_selected_products() +def highlight_product_related_task(sequence, spatial, product_type=None): + products = spatial.get_selected_products() if products: if product_type == "Output": tasks = sequence.find_related_output_tasks(products[0]) diff --git a/src/blenderbim/blenderbim/core/spatial.py b/src/blenderbim/blenderbim/core/spatial.py index 6668bc9335..3d209024f5 100644 --- a/src/blenderbim/blenderbim/core/spatial.py +++ b/src/blenderbim/blenderbim/core/spatial.py @@ -91,7 +91,4 @@ def select_similar_container(ifc, spatial, obj=None): element = ifc.get_entity(obj) if not element: return - for subelement in spatial.get_decomposed_elements(spatial.get_container(element)): - obj = ifc.get_object(subelement) - if obj: - spatial.select_object(obj) + spatial.select_products(products=spatial.get_decomposed_elements(spatial.get_container(element))) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 247376ed50..113c116ef7 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -498,6 +498,9 @@ class Root: class Selector: def set_active(cls, obj): pass +@interface +class Search: + def from_selector_query(cls, query): pass @interface class Sequence: @@ -548,7 +551,7 @@ class Sequence: def get_recurrence_pattern_attributes(cls, recurrence_pattern): pass def get_recurrence_pattern_times(cls): pass def get_rel_sequence_attributes(cls): pass - def get_selected_products(cls): pass + def get_selected_resource(cls): pass def get_start_date(cls): pass def get_task_attribute_value(cls, attribute_name): pass @@ -580,37 +583,42 @@ class Sequence: def load_work_plan_attributes(cls, work_plan): pass def load_work_schedule_attributes(cls, work_schedule): pass def load_work_time_attributes(cls, work_time): pass - def override_end_date(cls): pass def process_construction_state(cls, work_schedule, date): pass def process_task_status(cls, task, date): pass def remove_task_column(cls, name): pass def reset_time_period(cls): pass - def select_products(cls, products): pass def set_object_shading(cls): pass def set_task_sort_column(cls, column): pass def setup_default_task_columns(cls): pass def show_snapshot(cls, product_states): pass def update_visualisation_date(cls, start_date, finish_date): pass - @interface class Spatial: def can_contain(cls, structure_obj, element_obj): pass def can_reference(cls, structure, element): pass + def copy_xy(cls, src_obj, destination_obj): pass + def deselect_objects(cls): pass def disable_editing(cls, obj): pass def duplicate_object_and_data(cls, obj): pass def enable_editing(cls, obj): pass + def filter_products(cls, products, action): pass def get_container(cls, element): pass def get_decomposed_elements(cls, container): pass def get_object_matrix(cls, obj): pass def get_relative_object_matrix(cls, target_obj, relative_to_obj): pass + def get_selected_product_types(cls): pass + def get_selected_products_and_types(cls): pass + def get_selected_products(cls): pass + def get_selected_products(cls): pass def import_containers(cls, parent=None): pass def run_root_copy_class(cls, obj=None): pass def run_spatial_assign_container(cls, structure_obj=None, element_obj=None): pass def select_object(cls, obj): pass + def select_products(cls, products, unhide): pass def set_active_object(cls, obj): pass def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass - + def show_scene_objects(cls): pass @interface class Structural: diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index 915953a095..f011bf6039 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -50,4 +50,5 @@ from blenderbim.tool.surveyor import Surveyor from blenderbim.tool.system import System from blenderbim.tool.type import Type from blenderbim.tool.unit import Unit +from blenderbim.tool.search import Search from blenderbim.tool.cost import Cost \ No newline at end of file diff --git a/src/blenderbim/blenderbim/tool/resource.py b/src/blenderbim/blenderbim/tool/resource.py index 159631a8a8..e84a8237c5 100644 --- a/src/blenderbim/blenderbim/tool/resource.py +++ b/src/blenderbim/blenderbim/tool/resource.py @@ -286,14 +286,6 @@ class Resource(blenderbim.core.tool.Resource): contracted_resources.append(resource.id()) props.contracted_resources = json.dumps(contracted_resources) - @classmethod - def get_selected_products(cls): - return [ - tool.Ifc.get_entity(obj) - for obj in bpy.context.selected_objects - if obj.BIMObjectProperties.ifc_definition_id - ] or [] - @classmethod def import_resources(cls, file_path): from ifc4d.csv2ifc import Csv2Ifc @@ -304,3 +296,11 @@ class Resource(blenderbim.core.tool.Resource): p62ifc.file = tool.Ifc.get() p62ifc.execute() print("Importing Resources CSV finished in {:.2f} seconds".format(time.time() - start)) + + @classmethod + def get_highlighted_resource(cls): + return tool.Ifc.get().by_id( + bpy.context.scene.BIMResourceTreeProperties.resources[ + bpy.context.scene.BIMResourceProperties.active_resource_index + ].ifc_definition_id + ) \ No newline at end of file diff --git a/src/blenderbim/blenderbim/tool/search.py b/src/blenderbim/blenderbim/tool/search.py new file mode 100644 index 0000000000..3448ac1ee4 --- /dev/null +++ b/src/blenderbim/blenderbim/tool/search.py @@ -0,0 +1,11 @@ +import bpy +import blenderbim.core.tool +import blenderbim.tool as tool +from ifcopenshell.util.selector import Selector + + +class Search(blenderbim.core.tool.Search): + @classmethod + def from_selector_query(cls, query): + """Returns a list of products from a selector query""" + return Selector().parse(tool.Ifc.get(), query) diff --git a/src/blenderbim/blenderbim/tool/sequence.py b/src/blenderbim/blenderbim/tool/sequence.py index 30c1ce4982..2c6b8cb929 100644 --- a/src/blenderbim/blenderbim/tool/sequence.py +++ b/src/blenderbim/blenderbim/tool/sequence.py @@ -329,14 +329,6 @@ class Sequence(blenderbim.core.tool.Sequence): props.task_attributes.clear() blenderbim.bim.helper.import_attributes2(task, props.task_attributes) - @classmethod - def get_selected_products(cls): - return [ - tool.Ifc.get_entity(obj) - for obj in bpy.context.selected_objects - if obj.BIMObjectProperties.ifc_definition_id - ] or [] - @classmethod def enable_editing_task(cls, task): props = bpy.context.scene.BIMWorkScheduleProperties diff --git a/src/blenderbim/blenderbim/tool/spatial.py b/src/blenderbim/blenderbim/tool/spatial.py index 9c6478253f..9952ceb3b9 100644 --- a/src/blenderbim/blenderbim/tool/spatial.py +++ b/src/blenderbim/blenderbim/tool/spatial.py @@ -133,3 +133,55 @@ class Spatial(blenderbim.core.tool.Spatial): @classmethod def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): target_obj.matrix_world = relative_to_obj.matrix_world @ matrix + + @classmethod + def select_products(cls, products, unhide=False): + bpy.ops.object.select_all(action="DESELECT") + for product in products: + obj = tool.Ifc.get_object(product) + if obj: + obj.select_set(True) + if unhide: + obj.hide_set(False) + + @classmethod + def filter_products(cls, products, action): + objects = [tool.Ifc.get_object(product) for product in products if tool.Ifc.get_object(product)] + if action == "select": + [obj.select_set(True) for obj in objects] + elif action == "isolate": + [obj.hide_set(False) for obj in objects] + [obj.hide_set(True) for obj in bpy.context.visible_objects if not obj in objects] # this is slow + elif action == "unhide": + [obj.hide_set(False) for obj in objects] + elif action == "hide": + [obj.hide_set(True) for obj in objects] + + @classmethod + def deselect_objects(cls): + [obj.select_set(False) for obj in bpy.context.selected_objects] + # bpy.ops.object.select_all(action='DESELECT') + + @classmethod + def show_scene_objects(cls): + [obj.hide_set(False) for obj in bpy.data.scenes["Scene"].objects] + + @classmethod + def get_selected_products(cls): + for obj in bpy.context.selected_objects: + entity = tool.Ifc.get_entity(obj) + if entity and entity.is_a("IfcProduct"): + yield entity + + @classmethod + def get_selected_product_types(cls): + for obj in bpy.context.selected_objects: + entity = tool.Ifc.get_entity(obj) + if entity and entity.is_a("IfcTypeProduct"): + yield entity + + @classmethod + def copy_xy(cls, src_obj, destination_obj): + z = src_obj.location[2] + src_obj.location = (destination_obj.location[0], destination_obj.location[1], z) +