BBIM 4D features & fixes:

- feature to re-order tasks
- fixes for task sorting
- further workSchedule UI/UX improvements
- forgotten bits and bobs
This commit is contained in:
Sigma Dimensions
2023-04-30 15:44:13 +01:00
parent 2aa5e9d808
commit 55250aba6d
12 changed files with 403 additions and 104 deletions
@@ -97,6 +97,7 @@ classes = (
operator.RemoveWorkPlan, operator.RemoveWorkPlan,
operator.RemoveWorkSchedule, operator.RemoveWorkSchedule,
operator.RemoveWorkTime, operator.RemoveWorkTime,
operator.ReorderTask,
operator.SelectTaskRelatedProducts, operator.SelectTaskRelatedProducts,
operator.SelectTaskRelatedInputs, operator.SelectTaskRelatedInputs,
operator.SelectWorkScheduleProducts, operator.SelectWorkScheduleProducts,
@@ -223,6 +223,9 @@ class SequenceData:
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl: if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl:
if rel.RelatingControl.is_a("IfcWorkCalendar"): if rel.RelatingControl.is_a("IfcWorkCalendar"):
data["HasAssignmentsWorkCalendar"].append(rel.RelatingControl.id()) data["HasAssignmentsWorkCalendar"].append(rel.RelatingControl.id())
data["NestingIndex"] = None
for rel in task.Nests or []:
data["NestingIndex"] = rel.RelatedObjects.index(task)
cls.data["tasks"][task.id()] = data cls.data["tasks"][task.id()] = data
@classmethod @classmethod
@@ -275,13 +275,13 @@ class EditTaskTime(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingTask(bpy.types.Operator): class EnableEditingTask(bpy.types.Operator):
bl_idname = "bim.enable_editing_task" bl_idname = "bim.enable_editing_task_attributes"
bl_label = "Enable Editing Task" bl_label = "Enable Editing Task Attributes"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty() task: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
core.enable_editing_task(tool.Sequence, task=tool.Ifc.get().by_id(self.task)) core.enable_editing_task_attributes(tool.Sequence, task=tool.Ifc.get().by_id(self.task))
return {"FINISHED"} return {"FINISHED"}
@@ -1295,7 +1295,7 @@ class CopyTask(bpy.types.Operator, tool.Ifc.Operator):
class LoadProductTasks(bpy.types.Operator): class LoadProductTasks(bpy.types.Operator):
bl_idname = "bim.load_product_tasks" bl_idname = "bim.load_product_related_tasks"
bl_label = "Load Product Tasks" bl_label = "Load Product Tasks"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@@ -1310,7 +1310,7 @@ class LoadProductTasks(bpy.types.Operator):
return True return True
def execute(self, context): def execute(self, context):
core.load_product_tasks( core.load_product_related_tasks(
tool.Sequence, product=tool.Ifc.get().by_id(context.active_object.BIMObjectProperties.ifc_definition_id) tool.Sequence, product=tool.Ifc.get().by_id(context.active_object.BIMObjectProperties.ifc_definition_id)
) )
return {"FINISHED"} return {"FINISHED"}
@@ -1355,3 +1355,18 @@ class SelectUnassignedWorkScheduleProducts(bpy.types.Operator):
if isinstance(r, str): if isinstance(r, str):
self.report({"WARNING"}, r) self.report({"WARNING"}, r)
return {"FINISHED"} return {"FINISHED"}
class ReorderTask(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.reorder_task_nesting"
bl_label = "Reorder Nesting"
bl_options = {"REGISTER", "UNDO"}
new_index: bpy.props.IntProperty()
task: bpy.props.IntProperty()
def _execute(self, context):
r = core.reorder_task_nesting(
tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task), new_index=self.new_index
)
if isinstance(r, str):
self.report({"WARNING"}, r)
@@ -284,9 +284,14 @@ def update_color_progress(self, context):
color[1] = color_progress.g color[1] = color_progress.g
color[2] = color_progress.b color[2] = color_progress.b
def update_sort_reversed(self, context): def update_sort_reversed(self, context):
if context.scene.BIMWorkScheduleProperties.active_work_schedule_id: if context.scene.BIMWorkScheduleProperties.active_work_schedule_id:
core.create_task_tree(tool.Sequence, work_schedule=tool.Ifc.get().by_id(context.scene.BIMWorkScheduleProperties.active_work_schedule_id)) core.load_task_tree(
tool.Sequence,
work_schedule=tool.Ifc.get().by_id(context.scene.BIMWorkScheduleProperties.active_work_schedule_id),
)
class Task(PropertyGroup): class Task(PropertyGroup):
name: StringProperty(name="Name", update=updateTaskName) name: StringProperty(name="Name", update=updateTaskName)
@@ -359,7 +364,8 @@ class BIMWorkScheduleProperties(PropertyGroup):
active_task_id: IntProperty(name="Active Task Id") active_task_id: IntProperty(name="Active Task Id")
task_attributes: CollectionProperty(name="Task Attributes", type=Attribute) task_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False) should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False)
should_show_bar_visual_option: BoolProperty(name="Add to task bar", default=False) should_show_task_bar_selection: BoolProperty(name="Add to task bar", default=False)
should_show_snapshot_ui: BoolProperty(name="Should Show Snapshot UI", default=False)
should_show_column_ui: BoolProperty(name="Should Show Column UI", default=False) should_show_column_ui: BoolProperty(name="Should Show Column UI", default=False)
columns: CollectionProperty(name="Columns", type=Attribute) columns: CollectionProperty(name="Columns", type=Attribute)
active_column_index: IntProperty(name="Active Column Index") active_column_index: IntProperty(name="Active Column Index")
@@ -417,6 +423,8 @@ class BIMWorkScheduleProperties(PropertyGroup):
product_output_tasks: CollectionProperty(name="Product Task Outputs", type=TaskProduct) product_output_tasks: CollectionProperty(name="Product Task Outputs", type=TaskProduct)
active_product_output_task_index: IntProperty(name="Active Product Output Task Index") active_product_output_task_index: IntProperty(name="Active Product Output Task Index")
active_product_input_task_index: IntProperty(name="Active Product Input Task Index") active_product_input_task_index: IntProperty(name="Active Product Input Task Index")
enable_reorder: BoolProperty(name="Enable Reorder", default=False)
show_task_operators: BoolProperty(name="Show Task Options", default=True)
class BIMTaskTreeProperties(PropertyGroup): class BIMTaskTreeProperties(PropertyGroup):
@@ -170,7 +170,9 @@ class BIM_PT_work_schedules(Panel):
row1 = col.row(align=True) row1 = col.row(align=True)
row1.alignment = "RIGHT" row1.alignment = "RIGHT"
row1.prop(self.props, "should_show_column_ui", text="Schedule Columns", icon="SHORTDISPLAY") row1.prop(self.props, "should_show_column_ui", text="Schedule Columns", icon="SHORTDISPLAY")
row1.prop(self.props, "should_show_visualisation_ui", text="Animation Options", icon="CAMERA_STEREO") row2 = col.row(align=True)
row2.prop(self.props, "should_show_visualisation_ui", text="Animation Options", icon="CAMERA_STEREO")
row2.prop(self.props, "should_show_snapshot_ui", text="Snapshot Options", icon="CAMERA_STEREO")
row.operator("bim.disable_editing_work_schedule", text="Disable editing", icon="CANCEL") row.operator("bim.disable_editing_work_schedule", text="Disable editing", icon="CANCEL")
else: else:
row.operator( row.operator(
@@ -189,6 +191,8 @@ class BIM_PT_work_schedules(Panel):
self.draw_column_ui() self.draw_column_ui()
if self.props.should_show_visualisation_ui: if self.props.should_show_visualisation_ui:
self.draw_visualisation_ui() self.draw_visualisation_ui()
if self.props.should_show_snapshot_ui:
self.draw_snapshot_ui()
self.draw_editable_task_ui(work_schedule_id) self.draw_editable_task_ui(work_schedule_id)
def draw_task_operators(self): def draw_task_operators(self):
@@ -206,14 +210,23 @@ class BIM_PT_work_schedules(Panel):
row.operator("bim.edit_task", text="", icon="CHECKMARK") row.operator("bim.edit_task", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_task", text="", icon="CANCEL") row.operator("bim.disable_editing_task", text="", icon="CANCEL")
else: else:
row.prop(self.props, "should_show_bar_visual_option", text="", icon="NLA_PUSHDOWN") row.prop(self.props, "show_task_operators", text="Edit", icon="GREASEPENCIL")
row.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING").task = ifc_definition_id if self.props.show_task_operators:
row.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id row2 = self.layout.row(align=True)
row.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = ifc_definition_id row2.alignment = "RIGHT"
row.operator("bim.enable_editing_task", text="", icon="GREASEPENCIL").task = ifc_definition_id
row.operator("bim.add_task", text="", icon="ADD").task = ifc_definition_id row2.prop(self.props, "enable_reorder", text="", icon="SORTALPHA")
row.operator("bim.duplicate_task", text="", icon="DUPLICATE").task = ifc_definition_id row2.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING").task = ifc_definition_id
row.operator("bim.remove_task", text="", icon="X").task = ifc_definition_id row2.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id
row2.operator(
"bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO"
).task = ifc_definition_id
row2.operator(
"bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL"
).task = ifc_definition_id
row.operator("bim.add_task", text="Add", icon="ADD").task = ifc_definition_id
row.operator("bim.duplicate_task", text="Copy", icon="DUPLICATE").task = ifc_definition_id
row.operator("bim.remove_task", text="Delete", icon="X").task = ifc_definition_id
def draw_column_ui(self): def draw_column_ui(self):
row = self.layout.row() row = self.layout.row()
@@ -281,26 +294,35 @@ class BIM_PT_work_schedules(Panel):
row.prop(self.animation_props, "should_show_task_bar_options", text="Task Bar", icon="NLA_PUSHDOWN") row.prop(self.animation_props, "should_show_task_bar_options", text="Task Bar", icon="NLA_PUSHDOWN")
if self.animation_props.should_show_task_bar_options: if self.animation_props.should_show_task_bar_options:
row = self.layout.row() row = self.layout.row()
row.operator("bim.add_task_bars", text="Add Bar Visual", icon="NLA_PUSHDOWN") row.label(text="Task Bar Options", icon="NLA_PUSHDOWN")
row.alignment = "LEFT"
row = self.layout.row(align=True)
row.prop(self.props, "should_show_task_bar_selection", text="Enable Selection", icon="NLA_PUSHDOWN")
row.operator("bim.add_task_bars", text="Generate bars", icon="NLA_PUSHDOWN")
grid = self.layout.grid_flow(columns=2, even_columns=True) grid = self.layout.grid_flow(columns=2, even_columns=True)
# Column1 # Column1
col = grid.column() col = grid.column()
row1 = col.row(align=True)
row1.label(text="Bar Colors", icon="NLA_PUSHDOWN")
row2 = col.row(align=True) row = col.row(align=True)
row2.prop(self.animation_props, "color_progress") row.prop(self.animation_props, "color_progress")
row3 = col.row(align=True) row = col.row(align=True)
row3.prop(self.animation_props, "color_full") row.prop(self.animation_props, "color_full")
if self.animation_props.is_editing: if self.animation_props.is_editing:
self.draw_visualisation_settings_ui() self.draw_visualisation_settings_ui()
row = self.layout.row() row = self.layout.row(align=True)
op = row.operator("bim.visualise_work_schedule_date_range", text="Create Animation", icon="OUTLINER_OB_CAMERA") op = row.operator("bim.visualise_work_schedule_date_range", text="Create Animation", icon="OUTLINER_OB_CAMERA")
op.work_schedule = self.props.active_work_schedule_id op.work_schedule = self.props.active_work_schedule_id
def draw_snapshot_ui(self):
row = self.layout.row(align=True)
row.label(text="Create Construction Snapshot:")
row = self.layout.row(align=True)
op = row.operator("bim.datepicker", text=self.props.visualisation_start or "Date", icon="REW")
op.target_prop = "BIMWorkScheduleProperties.visualisation_start"
op = row.operator("bim.visualise_work_schedule_date", text="Create SnapShot", icon="RESTRICT_RENDER_OFF") op = row.operator("bim.visualise_work_schedule_date", text="Create SnapShot", icon="RESTRICT_RENDER_OFF")
op.work_schedule = self.props.active_work_schedule_id op.work_schedule = self.props.active_work_schedule_id
@@ -572,7 +594,7 @@ class BIM_UL_task_resources(UIList):
if item: if item:
row = layout.row(align=True) row = layout.row(align=True)
row.prop(item, "name", emboss=False, text="") row.prop(item, "name", emboss=False, text="")
row.prop(item, "schedule_usage", emboss=False, text="") row.label(text=str(item.schedule_usage))
class BIM_UL_animation_colors(UIList): class BIM_UL_animation_colors(UIList):
@@ -636,7 +658,7 @@ class BIM_UL_tasks(UIList):
text="", text="",
emboss=False, emboss=False,
) )
if self.props.should_show_bar_visual_option: if self.props.should_show_task_bar_selection:
row.prop( row.prop(
item, item,
"has_bar_visual", "has_bar_visual",
@@ -644,6 +666,8 @@ class BIM_UL_tasks(UIList):
text="", text="",
emboss=False, emboss=False,
) )
if self.props.enable_reorder:
self.draw_order_operator(row, item.ifc_definition_id)
if self.props.active_task_id: if self.props.active_task_id:
if self.props.editing_task_type == "SEQUENCE" and self.props.active_task_id != item.ifc_definition_id: if self.props.editing_task_type == "SEQUENCE" and self.props.active_task_id != item.ifc_definition_id:
if item.is_predecessor: if item.is_predecessor:
@@ -658,6 +682,18 @@ class BIM_UL_tasks(UIList):
op = row.operator("bim.assign_successor", text="", icon="TRACKING_FORWARDS", emboss=False) op = row.operator("bim.assign_successor", text="", icon="TRACKING_FORWARDS", emboss=False)
op.task = item.ifc_definition_id op.task = item.ifc_definition_id
def draw_order_operator(self, row, ifc_definition_id):
task = SequenceData.data["tasks"][ifc_definition_id]
if task["NestingIndex"] is not None:
if task["NestingIndex"] == 0:
op = row.operator("bim.reorder_task_nesting", icon="TRIA_DOWN", text="")
op.task = ifc_definition_id
op.new_index = task["NestingIndex"] + 1
elif task["NestingIndex"] > 0:
op = row.operator("bim.reorder_task_nesting", icon="TRIA_UP", text="")
op.task = ifc_definition_id
op.new_index = task["NestingIndex"] - 1
def draw_hierarchy(self, row, item): def draw_hierarchy(self, row, item):
for i in range(0, item.level_index): for i in range(0, item.level_index):
row.label(text="", icon="BLANK1") row.label(text="", icon="BLANK1")
@@ -878,7 +914,7 @@ class BIM_PT_4D_Tools(Panel):
def draw(self, context): def draw(self, context):
self.props = context.scene.BIMWorkScheduleProperties self.props = context.scene.BIMWorkScheduleProperties
row = self.layout.row() row = self.layout.row()
row.operator("bim.load_product_tasks", text="Load Tasks", icon="FILE_REFRESH") row.operator("bim.load_product_related_tasks", text="Load Tasks", icon="FILE_REFRESH")
grid = self.layout.grid_flow(columns=2, even_columns=True) grid = self.layout.grid_flow(columns=2, even_columns=True)
col1 = grid.column() col1 = grid.column()
@@ -170,3 +170,15 @@ def unassign_resource(ifc, spatial, resource=None, products=None):
products = spatial.get_selected_products() products = spatial.get_selected_products()
for product in products: for product in products:
ifc.run("resource.unassign_resource", relating_resource=resource, related_object=product) ifc.run("resource.unassign_resource", relating_resource=resource, related_object=product)
def edit_productivity_pset(ifc, resource_tool):
resource = resource_tool.get_highlighted_resource()
if resource is None:
return
productivity = resource_tool.get_productivity(resource)
if productivity:
pset = ifc.get().by_id(productivity["id"])
else:
pset = ifc.run("pset.add_pset", product=resource, name="EPset_Productivity")
ifc.run("pset.edit_pset", pset=pset, properties=resource_tool.get_productivity_attributes())
+32 -15
View File
@@ -74,47 +74,47 @@ def enable_editing_work_schedule(sequence, work_schedule=None):
def enable_editing_work_schedule_tasks(sequence, work_schedule=None): def enable_editing_work_schedule_tasks(sequence, work_schedule=None):
sequence.enable_editing_work_schedule_tasks(work_schedule) sequence.enable_editing_work_schedule_tasks(work_schedule)
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def create_task_tree(sequence, work_schedule): def load_task_tree(sequence, work_schedule):
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def expand_task(sequence, task=None): def expand_task(sequence, task=None):
sequence.expand_task(task) sequence.expand_task(task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def expand_all_tasks(sequence): def expand_all_tasks(sequence):
sequence.expand_all_tasks() sequence.expand_all_tasks()
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def contract_task(sequence, task=None): def contract_task(sequence, task=None):
sequence.contract_task(task) sequence.contract_task(task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def contract_all_tasks(sequence): def contract_all_tasks(sequence):
sequence.contract_all_tasks() sequence.contract_all_tasks()
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def remove_task(ifc, sequence, task=None): def remove_task(ifc, sequence, task=None):
ifc.run("sequence.remove_task", task=task) ifc.run("sequence.remove_task", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
sequence.disable_selecting_deleted_task() sequence.disable_selecting_deleted_task()
@@ -129,21 +129,24 @@ def disable_editing_work_schedule(sequence):
def add_summary_task(ifc, sequence, work_schedule=None): def add_summary_task(ifc, sequence, work_schedule=None):
ifc.run("sequence.add_task", work_schedule=work_schedule) ifc.run("sequence.add_task", work_schedule=work_schedule)
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def add_task(ifc, sequence, parent_task=None): def add_task(ifc, sequence, parent_task=None):
ifc.run("sequence.add_task", parent_task=parent_task) ifc.run("sequence.add_task", parent_task=parent_task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def enable_editing_task(sequence, task=None): def enable_editing_task(sequence, task=None):
sequence.load_task_attributes(task)
sequence.enable_editing_task(task) sequence.enable_editing_task(task)
def enable_editing_task_attributes(sequence, task=None):
sequence.load_task_attributes(task)
sequence.enable_editing_task_attributes(task)
def edit_task(ifc, sequence, task=None): def edit_task(ifc, sequence, task=None):
attributes = sequence.get_task_attributes() attributes = sequence.get_task_attributes()
@@ -165,7 +168,7 @@ def copy_task_attribute(ifc, sequence, attribute_name=None):
def duplicate_task(ifc, sequence, task=None): def duplicate_task(ifc, sequence, task=None):
ifc.run("sequence.duplicate_task", task=task) ifc.run("sequence.duplicate_task", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
@@ -464,7 +467,7 @@ def calculate_task_duration(ifc, sequence, task=None):
ifc.run("sequence.calculate_task_duration", task=task) ifc.run("sequence.calculate_task_duration", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
if work_schedule: if work_schedule:
sequence.create_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
@@ -473,6 +476,8 @@ def highlight_task(sequence, task=None):
is_work_schedule_active = sequence.is_work_schedule_active(work_schedule) is_work_schedule_active = sequence.is_work_schedule_active(work_schedule)
if is_work_schedule_active: if is_work_schedule_active:
sequence.highlight_task(task) sequence.highlight_task(task)
else:
return "Work schedule is not active"
def highlight_product_related_task(sequence, spatial, product_type=None): def highlight_product_related_task(sequence, spatial, product_type=None):
@@ -537,5 +542,17 @@ def generate_gantt_chart(sequence, work_schedule):
sequence.generate_gantt_browser_chart(json) sequence.generate_gantt_browser_chart(json)
def load_product_tasks(sequence, product=None): def load_product_related_tasks(sequence, product=None):
sequence.load_product_tasks(product) sequence.load_product_related_tasks(product)
def reorder_task_nesting(ifc, sequence, task, new_index):
is_sorting_enabled = sequence.is_sorting_enabled()
is_sort_reversed = sequence.is_sort_reversed()
if is_sorting_enabled or is_sort_reversed:
return "Remove manual sorting"
else:
ifc.run("nest.reorder_nesting", item= task, new_index= new_index)
work_schedule= sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule)
sequence.load_task_properties()
+27 -22
View File
@@ -562,32 +562,37 @@ class Qto:
@interface @interface
class Resource: class Resource:
def load_resources(cls): pass def clear_productivity_data(cls, props): pass
def load_resource_properties(cls): pass def contract_resource(cls, resource): pass
def disable_editing_resource_cost_value(cls): pass
def disable_editing_resource_quantity(cls): pass
def disable_editing_resource(cls): pass def disable_editing_resource(cls): pass
def disable_resource_editing_ui(cls): pass def disable_resource_editing_ui(cls): pass
def load_resource_attributes(cls, resource): pass def edit_productivity_pset(cls, resource, attributes): pass
def enable_editing_resource(cls, resource): pass
def get_resource_attributes(cls): pass
def enable_editing_resource_time(cls, resource): pass
def get_resource_time(cls, resource): pass
def load_resource_time_attributes(cls, resource_time): pass
def get_resource_time_attributes(cls): pass
def enable_editing_resource_costs(cls, resource): pass
def disable_editing_resource_cost_value(cls): pass
def enable_editing_resource_cost_value_formula(cls, cost_value): pass
def load_cost_value_attributes(cls, cost_value): pass
def enable_editing_cost_value_attributes(cls, cost_value): pass def enable_editing_cost_value_attributes(cls, cost_value): pass
def get_resource_cost_value_formula(cls): pass
def get_resource_cost_value_attributes(cls): pass
def enable_editing_resource_base_quantity(cls, resource): pass def enable_editing_resource_base_quantity(cls, resource): pass
def enable_editing_resource_cost_value_formula(cls, cost_value): pass
def enable_editing_resource_costs(cls, resource): pass
def enable_editing_resource_quantity(cls, resource_quantity): pass def enable_editing_resource_quantity(cls, resource_quantity): pass
def disable_editing_resource_quantity(cls): pass def enable_editing_resource_time(cls, resource): pass
def get_resource_quantity_attributes(cls): pass def enable_editing_resource(cls, resource): pass
def expand_resource(cls, resource): pass def expand_resource(cls, resource): pass
def contract_resource(cls, resource): pass def get_highlighted_resource(cls): pass
def get_productivity_attributes(cls): pass
def get_productivity(cls, resource, should_inherit): pass
def get_resource_attributes(cls): pass
def get_resource_cost_value_attributes(cls): pass
def get_resource_cost_value_formula(cls): pass
def get_resource_quantity_attributes(cls): pass
def get_resource_time_attributes(cls): pass
def get_resource_time(cls, resource): pass
def import_resources(cls, file_path): pass def import_resources(cls, file_path): pass
def load_cost_value_attributes(cls, cost_value): pass
def load_productivity_data(cls): pass
def load_resource_attributes(cls, resource): pass
def load_resource_properties(cls): pass
def load_resource_time_attributes(cls, resource_time): pass
def load_resources(cls): pass
@interface @interface
class Root: class Root:
@@ -635,7 +640,7 @@ class Sequence:
def contract_task(cls, task): pass def contract_task(cls, task): pass
def create_bars(cls, tasks): pass def create_bars(cls, tasks): pass
def create_new_task_json(cls, task, json, type_map=None): pass def create_new_task_json(cls, task, json, type_map=None): pass
def create_task_tree(cls, work_schedule): pass def load_task_tree(cls, work_schedule): pass
def create_tasks_json(cls, work_schedule=None): pass def create_tasks_json(cls, work_schedule=None): pass
def disable_editing_rel_sequence(cls): pass def disable_editing_rel_sequence(cls): pass
def disable_editing_task_animation_colors(cls): pass def disable_editing_task_animation_colors(cls): pass
@@ -653,7 +658,7 @@ class Sequence:
def enable_editing_task_calendar(cls, task): pass def enable_editing_task_calendar(cls, task): pass
def enable_editing_task_sequence(cls, task): pass def enable_editing_task_sequence(cls, task): pass
def enable_editing_task_time(cls, task): pass def enable_editing_task_time(cls, task): pass
def enable_editing_task(cls, task): pass def enable_editing_task_attributes(cls, task): pass
def enable_editing_work_calendar_times(cls, work_calendar): pass def enable_editing_work_calendar_times(cls, work_calendar): pass
def enable_editing_work_calendar(cls, work_calendar): pass def enable_editing_work_calendar(cls, work_calendar): pass
def enable_editing_work_plan_schedules(cls, work_plan): pass def enable_editing_work_plan_schedules(cls, work_plan): pass
@@ -700,7 +705,7 @@ class Sequence:
def highlight_task(cls, task): pass def highlight_task(cls, task): pass
def is_work_schedule_active(cls, work_schedule): pass def is_work_schedule_active(cls, work_schedule): pass
def load_lag_time_attributes(cls, lag_time): pass def load_lag_time_attributes(cls, lag_time): pass
def load_product_tasks(cls, product): pass def load_product_related_tasks(cls, product): pass
def load_rel_sequence_attributes(cls, rel_sequence): pass def load_rel_sequence_attributes(cls, rel_sequence): pass
def load_resources(cls): pass def load_resources(cls): pass
def load_task_animation_colors(cls): pass def load_task_animation_colors(cls): pass
+82 -4
View File
@@ -30,6 +30,8 @@ from datetime import datetime
from dateutil import parser from dateutil import parser
import ifcopenshell.util.date as ifcdateutils import ifcopenshell.util.date as ifcdateutils
import ifcopenshell.util.cost import ifcopenshell.util.cost
import ifcopenshell.util.resource
import blenderbim.bim.schema
class Resource(blenderbim.core.tool.Resource): class Resource(blenderbim.core.tool.Resource):
@@ -58,6 +60,7 @@ class Resource(blenderbim.core.tool.Resource):
if not resource.HasContext: if not resource.HasContext:
continue continue
create_new_resource_li(resource, 0) create_new_resource_li(resource, 0)
cls.load_productivity_data()
props.is_editing = True props.is_editing = True
@classmethod @classmethod
@@ -299,8 +302,83 @@ class Resource(blenderbim.core.tool.Resource):
@classmethod @classmethod
def get_highlighted_resource(cls): def get_highlighted_resource(cls):
return tool.Ifc.get().by_id( resources = len(bpy.context.scene.BIMResourceTreeProperties.resources)
bpy.context.scene.BIMResourceTreeProperties.resources[ if resources and resources > bpy.context.scene.BIMResourceProperties.active_resource_index:
bpy.context.scene.BIMResourceProperties.active_resource_index return tool.Ifc.get().by_id(
bpy.context.scene.BIMResourceTreeProperties.resources[
bpy.context.scene.BIMResourceProperties.active_resource_index
].ifc_definition_id ].ifc_definition_id
) )
@classmethod
def clear_productivity_data(cls, props):
for duration_prop in props.quantity_consumed or []:
if duration_prop.name == "BaseQuantityConsumed":
duration_prop.years = 0
duration_prop.months = 0
duration_prop.days = 0
duration_prop.hours = 0
duration_prop.minutes = 0
duration_prop.seconds = 0
props.quantity_produced = 0
props.quantity_produced_name = ""
@classmethod
def load_productivity_data(cls):
duration_props = None
for collection_prop in bpy.context.scene.BIMResourceProductivity.quantity_consumed:
duration_props = collection_prop if collection_prop.name == "BaseQuantityConsumed" else None
break
if not duration_props:
duration_props = bpy.context.scene.BIMResourceProductivity.quantity_consumed.add()
duration_props.name = "BaseQuantityConsumed"
cls.clear_productivity_data(bpy.context.scene.BIMResourceProductivity)
current_resource = tool.Resource.get_highlighted_resource()
if current_resource:
productivity = cls.get_productivity(current_resource)
print("Resource:", current_resource, "productivity", productivity)
if productivity:
bpy.context.scene.BIMResourceProductivity.quantity_produced = (
ifcopenshell.util.resource.get_quantity_produced(productivity)
)
bpy.context.scene.BIMResourceProductivity.quantity_produced_name = (
ifcopenshell.util.resource.get_quantity_produced_name(productivity)
)
time_consumed = ifcopenshell.util.resource.get_unit_consumed(productivity)
if time_consumed:
durations_attributes = helper.parse_duration_as_blender_props(time_consumed)
duration_props.years = durations_attributes["years"]
duration_props.months = durations_attributes["months"]
duration_props.days = durations_attributes["days"]
duration_props.hours = durations_attributes["hours"]
duration_props.minutes = durations_attributes["minutes"]
duration_props.seconds = durations_attributes["seconds"]
@classmethod
def get_productivity_attributes(cls):
props = bpy.context.scene.BIMResourceProductivity
productivity = {}
if props.quantity_consumed:
productivity["BaseQuantityConsumed"] = helper.simplify_duration(
props.quantity_consumed, "ELAPSEDTIME", "BaseQuantityConsumed"
)
productivity["BaseQuantityProducedValue"] = props.quantity_produced
productivity["BaseQuantityProducedName"] = props.quantity_produced_name
return productivity
@classmethod
def get_productivity(cls, resource, should_inherit=False):
return ifcopenshell.util.resource.get_productivity(resource, should_inherit=should_inherit)
@classmethod
def edit_productivity_pset(cls, resource, attributes):
productivity = cls.get_productivity(resource)
if productivity:
pset = tool.Ifc.get().by_id(productivity["id"])
else:
pset = tool.Ifc.run("pset.add_pset", product=resource, name="EPset_Productivity")
tool.Ifc.run(
"pset.edit_pset",
pset=pset,
properties=attributes,
)
+45 -23
View File
@@ -27,6 +27,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.unit import ifcopenshell.util.unit
import json import json
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.core
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.helper import blenderbim.bim.helper
import blenderbim.bim.module.sequence.helper as helper import blenderbim.bim.module.sequence.helper as helper
@@ -132,7 +133,7 @@ class Sequence(blenderbim.core.tool.Sequence):
props.editing_type = "TASKS" props.editing_type = "TASKS"
@classmethod @classmethod
def create_task_tree(cls, work_schedule): def load_task_tree(cls, work_schedule):
bpy.context.scene.BIMTaskTreeProperties.tasks.clear() bpy.context.scene.BIMTaskTreeProperties.tasks.clear()
props = bpy.context.scene.BIMWorkScheduleProperties props = bpy.context.scene.BIMWorkScheduleProperties
cls.contracted_tasks = json.loads(props.contracted_tasks) cls.contracted_tasks = json.loads(props.contracted_tasks)
@@ -145,25 +146,26 @@ class Sequence(blenderbim.core.tool.Sequence):
def get_sorted_tasks_ids(cls, tasks): def get_sorted_tasks_ids(cls, tasks):
def get_sort_key(task): def get_sort_key(task):
# Sorting only applies to actual tasks, not the WBS # Sorting only applies to actual tasks, not the WBS
for rel in task.IsNestedBy: # for rel in task.IsNestedBy:
for object in rel.RelatedObjects: # for object in rel.RelatedObjects:
if object.is_a("IfcTask"): # if object.is_a("IfcTask"):
return "0000000000" + (task.Identification or "") # return "0000000000" + (task.Identification or "")
if not bpy.context.scene.BIMWorkScheduleProperties.sort_column:
return task.Identification or ""
column_type, name = bpy.context.scene.BIMWorkScheduleProperties.sort_column.split(".") column_type, name = bpy.context.scene.BIMWorkScheduleProperties.sort_column.split(".")
if column_type == "IfcTask": if column_type == "IfcTask":
return task.Name or "" return task.get_info(task)[name] or ""
elif column_type == "IfcTaskTime" and task.TaskTime: elif column_type == "IfcTaskTime" and task.TaskTime:
return task.TaskTime.Name or "" return task.TaskTime.get_info(task)[name]
return task.Identification or "" return task.Identification or ""
def natural_sort_key(i, _nsre=re.compile("([0-9]+)")): def natural_sort_key(i, _nsre=re.compile("([0-9]+)")):
s = sort_keys[i] s = sort_keys[i]
return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)] return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)]
sort_keys = {task.id(): get_sort_key(task) for task in tasks} if bpy.context.scene.BIMWorkScheduleProperties.sort_column:
related_object_ids = sorted(sort_keys, key=natural_sort_key) sort_keys = {task.id(): get_sort_key(task) for task in tasks}
related_object_ids = sorted(sort_keys, key=natural_sort_key)
else:
related_object_ids = [task.id() for task in tasks]
if bpy.context.scene.BIMWorkScheduleProperties.is_sort_reversed: if bpy.context.scene.BIMWorkScheduleProperties.is_sort_reversed:
related_object_ids.reverse() related_object_ids.reverse()
return related_object_ids return related_object_ids
@@ -328,7 +330,7 @@ class Sequence(blenderbim.core.tool.Sequence):
blenderbim.bim.helper.import_attributes2(task, props.task_attributes) blenderbim.bim.helper.import_attributes2(task, props.task_attributes)
@classmethod @classmethod
def enable_editing_task(cls, task): def enable_editing_task_attributes(cls, task):
props = bpy.context.scene.BIMWorkScheduleProperties props = bpy.context.scene.BIMWorkScheduleProperties
props.active_task_id = task.id() props.active_task_id = task.id()
props.editing_task_type = "ATTRIBUTES" props.editing_task_type = "ATTRIBUTES"
@@ -407,16 +409,15 @@ class Sequence(blenderbim.core.tool.Sequence):
def load_task_resources(cls, resources): def load_task_resources(cls, resources):
props = bpy.context.scene.BIMWorkScheduleProperties props = bpy.context.scene.BIMWorkScheduleProperties
props.task_resources.clear() props.task_resources.clear()
if resources: for resource in resources or []:
for resource in resources: new = props.task_resources.add()
new = props.task_resources.add() new.ifc_definition_id = resource.id()
new.ifc_definition_id = resource.id() new.name = resource.Name or "Unnamed"
new.name = resource.Name or "Unnamed" new.schedule_usage = resource.Usage.ScheduleUsage or 1 if resource.Usage else 0
new.schedule_usage = resource.Usage.ScheduleUsage or 1 if resource.Usage else 0
@classmethod @classmethod
def load_resources(cls): def load_resources(cls):
bpy.ops.bim.load_resources() # remove and refactor blenderbim.core.resource.load_resources(tool.Resource)
@classmethod @classmethod
def get_task_inputs(cls, task): def get_task_inputs(cls, task):
@@ -428,10 +429,22 @@ class Sequence(blenderbim.core.tool.Sequence):
is_deep = bpy.context.scene.BIMWorkScheduleProperties.show_nested_outputs is_deep = bpy.context.scene.BIMWorkScheduleProperties.show_nested_outputs
return ifcopenshell.util.sequence.get_task_outputs(task, is_deep) return ifcopenshell.util.sequence.get_task_outputs(task, is_deep)
@classmethod
def are_entities_same_class(cls, entities):
if not entities:
return False
if len(entities) == 1:
return True
first = entities[0]
for entity in entities:
if entity.is_a() != first.is_a():
return False
return True
@classmethod @classmethod
def get_task_resources(cls, task): def get_task_resources(cls, task):
is_deep = bpy.context.scene.BIMWorkScheduleProperties.show_nested_resources is_deep = bpy.context.scene.BIMWorkScheduleProperties.show_nested_resources
return ifcopenshell.util.sequence.get_task_resource(task, is_deep) return ifcopenshell.util.sequence.get_task_resources(task, is_deep)
@classmethod @classmethod
def load_task_inputs(cls, inputs): def load_task_inputs(cls, inputs):
@@ -732,6 +745,8 @@ class Sequence(blenderbim.core.tool.Sequence):
def remove_task_column(cls, name): def remove_task_column(cls, name):
props = bpy.context.scene.BIMWorkScheduleProperties props = bpy.context.scene.BIMWorkScheduleProperties
props.columns.remove(props.columns.find(name)) props.columns.remove(props.columns.find(name))
if props.sort_column == name:
props.sort_column = ""
@classmethod @classmethod
def set_task_sort_column(cls, column): def set_task_sort_column(cls, column):
@@ -779,7 +794,7 @@ class Sequence(blenderbim.core.tool.Sequence):
bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks = json.dumps(contracted_tasks) bpy.context.scene.BIMWorkScheduleProperties.contracted_tasks = json.dumps(contracted_tasks)
expand_ancestors(parent_task) expand_ancestors(parent_task)
work_schedule = cls.get_active_work_schedule() work_schedule = cls.get_active_work_schedule()
cls.create_task_tree(work_schedule) cls.load_task_tree(work_schedule)
cls.load_task_properties() cls.load_task_properties()
task_props = bpy.context.scene.BIMTaskTreeProperties task_props = bpy.context.scene.BIMTaskTreeProperties
@@ -1510,9 +1525,8 @@ class Sequence(blenderbim.core.tool.Sequence):
webbrowser.open("file://" + os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.html")) webbrowser.open("file://" + os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.html"))
@classmethod @classmethod
def load_product_tasks(cls, product): def load_product_related_tasks(cls, product):
props = bpy.context.scene.BIMWorkScheduleProperties props = bpy.context.scene.BIMWorkScheduleProperties
props.is_task_update_enabled = False
props.product_input_tasks.clear() props.product_input_tasks.clear()
props.product_output_tasks.clear() props.product_output_tasks.clear()
task_inputs, task_ouputs = ifcopenshell.util.sequence.get_tasks_for_product(product) task_inputs, task_ouputs = ifcopenshell.util.sequence.get_tasks_for_product(product)
@@ -1540,3 +1554,11 @@ class Sequence(blenderbim.core.tool.Sequence):
task_inputs = [task for task in task_inputs or [] if cls.get_work_schedule(task) == work_schedule] task_inputs = [task for task in task_inputs or [] if cls.get_work_schedule(task) == work_schedule]
task_ouputs = [task for task in task_ouputs or [] if cls.get_work_schedule(task) == work_schedule] task_ouputs = [task for task in task_ouputs or [] if cls.get_work_schedule(task) == work_schedule]
return bool(task_inputs or task_ouputs) return bool(task_inputs or task_ouputs)
@classmethod
def is_sorting_enabled(cls):
return bpy.context.scene.BIMWorkScheduleProperties.sort_column
@classmethod
def is_sort_reversed(cls):
return bpy.context.scene.BIMWorkScheduleProperties.is_sort_reversed
@@ -225,7 +225,7 @@ Scenario: Enable editing task
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
When I press "bim.enable_editing_task(task={task})" When I press "bim.enable_editing_task_attributes(task={task})"
Then nothing happens Then nothing happens
Scenario: Copy task attribute Scenario: Copy task attribute
@@ -236,7 +236,7 @@ Scenario: Copy task attribute
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes[2].string_value" to "Foo" And I set "scene.BIMWorkScheduleProperties.task_attributes[2].string_value" to "Foo"
When I set "scene.BIMTaskTreeProperties.tasks[1].is_selected" to "True" When I set "scene.BIMTaskTreeProperties.tasks[1].is_selected" to "True"
And I press "bim.copy_task_attribute(name='Description')" And I press "bim.copy_task_attribute(name='Description')"
@@ -253,7 +253,7 @@ Scenario: Unassign task Successor
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
And I press "bim.assign_successor(task={nested_task_two})" And I press "bim.assign_successor(task={nested_task_two})"
When I press "bim.unassign_successor(task={nested_task_two})" When I press "bim.unassign_successor(task={nested_task_two})"
Then nothing happens Then nothing happens
@@ -269,7 +269,7 @@ Scenario: Edit time Lag
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
When I press "bim.assign_successor(task={nested_task_two})" When I press "bim.assign_successor(task={nested_task_two})"
And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()" And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()"
When I press "bim.assign_lag_time(sequence={rel_sequence})" When I press "bim.assign_lag_time(sequence={rel_sequence})"
@@ -290,7 +290,7 @@ Scenario: Unassign time Lag
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
When I press "bim.assign_successor(task={nested_task_two})" When I press "bim.assign_successor(task={nested_task_two})"
And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()" And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()"
When I press "bim.assign_lag_time(sequence={rel_sequence})" When I press "bim.assign_lag_time(sequence={rel_sequence})"
@@ -309,7 +309,7 @@ Scenario: Edit Sequence Relationship
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
When I press "bim.assign_successor(task={nested_task_two})" When I press "bim.assign_successor(task={nested_task_two})"
And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()" And the variable "rel_sequence" is "IfcStore.get_file().by_type('IfcRelSequence')[0].id()"
And I press "bim.enable_editing_sequence_attributes(sequence={rel_sequence})" And I press "bim.enable_editing_sequence_attributes(sequence={rel_sequence})"
@@ -340,7 +340,7 @@ Scenario: Animate the construction of a wall
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "CONSTRUCTION" And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "CONSTRUCTION"
And I press "bim.edit_task" And I press "bim.edit_task"
And I press "bim.enable_editing_task_time(task={task})" And I press "bim.enable_editing_task_time(task={task})"
@@ -376,7 +376,7 @@ Scenario: Animate the demolition of a wall
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "DEMOLITION" And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "DEMOLITION"
And I press "bim.edit_task" And I press "bim.edit_task"
And I press "bim.enable_editing_task_time(task={task})" And I press "bim.enable_editing_task_time(task={task})"
@@ -415,7 +415,7 @@ Scenario: Animate the operation of a wall
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "OPERATION" And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "OPERATION"
And I press "bim.edit_task" And I press "bim.edit_task"
And I press "bim.enable_editing_task_time(task={task})" And I press "bim.enable_editing_task_time(task={task})"
@@ -448,7 +448,7 @@ Scenario: Animate the movement of a wall
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "MOVE" And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "MOVE"
And I press "bim.edit_task" And I press "bim.edit_task"
And I press "bim.enable_editing_task_time(task={task})" And I press "bim.enable_editing_task_time(task={task})"
@@ -539,7 +539,7 @@ Scenario: Generate Gantt Chart
And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})" And I press "bim.enable_editing_work_schedule_tasks(work_schedule={work_schedule})"
And I press "bim.add_summary_task(work_schedule={work_schedule})" And I press "bim.add_summary_task(work_schedule={work_schedule})"
And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()" And the variable "task" is "IfcStore.get_file().by_type('IfcTask')[0].id()"
And I press "bim.enable_editing_task(task={task})" And I press "bim.enable_editing_task_attributes(task={task})"
And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "CONSTRUCTION" And I set "scene.BIMWorkScheduleProperties.task_attributes.get('PredefinedType').enum_value" to "CONSTRUCTION"
And I press "bim.edit_task" And I press "bim.edit_task"
And I press "bim.enable_editing_task_time(task={task})" And I press "bim.enable_editing_task_time(task={task})"
@@ -788,7 +788,7 @@ Scenario: Duplicate Task
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
And I press "bim.assign_successor(task={nested_task_two})" And I press "bim.assign_successor(task={nested_task_two})"
When I press "bim.duplicate_task(task={task})" When I press "bim.duplicate_task(task={task})"
Then nothing happens Then nothing happens
@@ -804,7 +804,7 @@ Scenario: Duplicate Task and edit sequence Relationship
And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()" And the variable "nested_task_one" is "IfcStore.get_file().by_type('IfcTask')[1].id()"
When I press "bim.add_task(task={task})" When I press "bim.add_task(task={task})"
And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()" And the variable "nested_task_two" is "IfcStore.get_file().by_type('IfcTask')[2].id()"
And I press "bim.enable_editing_task(task={nested_task_one})" And I press "bim.enable_editing_task_attributes(task={nested_task_one})"
And I press "bim.assign_successor(task={nested_task_two})" And I press "bim.assign_successor(task={nested_task_two})"
And I press "bim.duplicate_task(task={task})" And I press "bim.duplicate_task(task={task})"
When I press "bim.enable_editing_task_sequence(task={nested_task_one})" When I press "bim.enable_editing_task_sequence(task={nested_task_one})"
@@ -0,0 +1,102 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell.util.element
import ifcopenshell.util.date
def get_productivity(resource, should_inherit=True):
productivity = ifcopenshell.util.element.get_psets(
resource
).get("EPset_Productivity", None)
if should_inherit and not productivity:
# Proposal for Schema - If instance doesn't have any productivity, inherit it's parent's productivity
if not resource.Nests:
return None
else:
parent_resource = resource.Nests[0].RelatingObject
productivity = ifcopenshell.util.element.get_psets(
parent_resource
).get("EPset_Productivity", None)
return productivity
def get_unit_consumed(productivity):
duration = productivity.get("BaseQuantityConsumed", None)
if not duration:
return
return ifcopenshell.util.date.ifc2datetime(duration)
def get_quantity_produced(productivity):
if not productivity:
return 0
return productivity.get("BaseQuantityProducedValue", 0)
def get_quantity_produced_name(productivity):
if not productivity:
return ""
return productivity.get("BaseQuantityProducedName", "")
def get_total_quantity_produced(resource, quantity_name_in_process):
def get_product_quantity(product, quantity_name):
psets = ifcopenshell.util.element.get_psets(product)
for pset in psets.values():
for name, value in pset.items():
if name == quantity_name:
return float(value)
total = 0
products = get_parametric_resource_products(resource)
if quantity_name_in_process == "Count":
total = len(products)
else:
for product in products:
total += get_product_quantity(product, quantity_name_in_process)
return total
def get_parametric_resource_products(resource):
products = []
for rel in resource.HasAssignments or []:
if not rel.is_a("IfcRelAssignsToProcess"):
continue
for rel2 in rel.RelatingProcess.HasAssignments or []:
if not rel2.is_a("IfcRelAssignsToProduct"):
continue
products.append(rel2.RelatingProduct)
return products
def get_resource_required_work(resource):
productivity = get_productivity(resource)
if productivity:
quantity_produced = get_quantity_produced(productivity)
time_consumed = get_unit_consumed(productivity)
quantity_name_in_process = get_quantity_produced_name(productivity)
total_quantity_to_produce = get_total_quantity_produced(resource, quantity_name_in_process)
if not time_consumed or not quantity_produced or not total_quantity_to_produce:
return
iso_string = ""
if "T" in productivity.get("BaseQuantityConsumed", ""):
seconds = (time_consumed.days * 24 * 60 * 60) + time_consumed.seconds
productivity_ratio = seconds / quantity_produced
required_work = total_quantity_to_produce * productivity_ratio
iso_string = f"PT{required_work / 60 / 60}H"
else:
days = time_consumed.days + (time_consumed.seconds / (24 * 60 * 60))
productivity_ratio = days / quantity_produced
required_work = total_quantity_to_produce * productivity_ratio
iso_string = f"P{required_work}D"
return iso_string