mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 19:07:57 +00:00
New feature to visualise construction progress at a particular date
This commit is contained in:
@@ -63,6 +63,8 @@ classes = (
|
||||
operator.ImportP6,
|
||||
operator.LoadTaskProperties,
|
||||
operator.SelectTaskRelatedProducts,
|
||||
operator.VisualiseWorkScheduleDate,
|
||||
operator.VisualiseWorkScheduleDateRange,
|
||||
prop.WorkPlan,
|
||||
prop.BIMWorkPlanProperties,
|
||||
prop.Task,
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
from ifcopenshell.api.sequence.data import Data
|
||||
|
||||
|
||||
def derive_date(ifc_definition_id, attribute_name, date=None, is_earliest=False, is_latest=False):
|
||||
task = Data.tasks[ifc_definition_id]
|
||||
if task["TaskTime"]:
|
||||
current_date = Data.task_times[task["TaskTime"]][attribute_name]
|
||||
if current_date:
|
||||
return current_date
|
||||
for subtask in task["RelatedObjects"]:
|
||||
current_date = derive_date(
|
||||
subtask, attribute_name, date=date, is_earliest=is_earliest, is_latest=is_latest
|
||||
)
|
||||
if is_earliest:
|
||||
if current_date and (date is None or current_date < date):
|
||||
date = current_date
|
||||
if is_latest:
|
||||
if current_date and (date is None or current_date > date):
|
||||
date = current_date
|
||||
return date
|
||||
@@ -7,6 +7,7 @@ import pystache
|
||||
import webbrowser
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.date
|
||||
import blenderbim.bim.module.sequence.helper as helper
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from dateutil import parser
|
||||
@@ -311,8 +312,8 @@ class LoadTaskProperties(bpy.types.Operator):
|
||||
isodate.duration_isoformat(task_time["ScheduleDuration"]) if task_time["ScheduleDuration"] else "-"
|
||||
)
|
||||
else:
|
||||
derived_start = self.derive_start(item.ifc_definition_id)
|
||||
derived_finish = self.derive_finish(item.ifc_definition_id)
|
||||
derived_start = helper.derive_date(item.ifc_definition_id, "ScheduleStart", is_earliest=True)
|
||||
derived_finish = helper.derive_date(item.ifc_definition_id, "ScheduleFinish", is_latest=True)
|
||||
item.derived_start = self.canonicalise_time(derived_start) if derived_start else ""
|
||||
item.derived_finish = self.canonicalise_time(derived_finish) if derived_finish else ""
|
||||
if derived_start and derived_finish:
|
||||
@@ -324,30 +325,6 @@ class LoadTaskProperties(bpy.types.Operator):
|
||||
self.props.is_task_update_enabled = True
|
||||
return {"FINISHED"}
|
||||
|
||||
def derive_start(self, ifc_definition_id, start=None):
|
||||
task = Data.tasks[ifc_definition_id]
|
||||
if task["TaskTime"]:
|
||||
schedule_start = Data.task_times[task["TaskTime"]]["ScheduleStart"]
|
||||
if schedule_start:
|
||||
return schedule_start
|
||||
for subtask in task["RelatedObjects"]:
|
||||
schedule_start = self.derive_start(subtask, start)
|
||||
if schedule_start and (start is None or schedule_start < start):
|
||||
start = schedule_start
|
||||
return start
|
||||
|
||||
def derive_finish(self, ifc_definition_id, finish=None):
|
||||
task = Data.tasks[ifc_definition_id]
|
||||
if task["TaskTime"]:
|
||||
schedule_finish = Data.task_times[task["TaskTime"]]["ScheduleFinish"]
|
||||
if schedule_finish:
|
||||
return schedule_finish
|
||||
for subtask in task["RelatedObjects"]:
|
||||
schedule_finish = self.derive_finish(subtask, finish)
|
||||
if schedule_finish and (finish is None or schedule_finish > finish):
|
||||
finish = schedule_finish
|
||||
return finish
|
||||
|
||||
def canonicalise_time(self, time):
|
||||
if not time:
|
||||
return "-"
|
||||
@@ -1421,3 +1398,72 @@ class SelectTaskRelatedProducts(bpy.types.Operator):
|
||||
if obj.BIMObjectProperties.ifc_definition_id in related_products:
|
||||
obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class VisualiseWorkScheduleDate(bpy.types.Operator):
|
||||
bl_idname = "bim.visualise_work_schedule_date"
|
||||
bl_label = "Visualise Work Schedule Date"
|
||||
work_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
self.file = IfcStore.get_file()
|
||||
self.date = parser.parse(props.visualisation_start, dayfirst=True, fuzzy=True)
|
||||
self.preprocess_tasks()
|
||||
for obj in bpy.data.objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
obj.color = (1.0, 1.0, 1.0, 1)
|
||||
obj.hide_set(False)
|
||||
if obj.BIMObjectProperties.ifc_definition_id in self.not_yet_started:
|
||||
obj.hide_set(True)
|
||||
elif obj.BIMObjectProperties.ifc_definition_id in self.started:
|
||||
obj.color = (0.0, 1.0, 0.0, 1)
|
||||
elif obj.BIMObjectProperties.ifc_definition_id in self.completed:
|
||||
pass
|
||||
else:
|
||||
obj.color = (1.0, 0.0, 0.0, 1)
|
||||
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
|
||||
area.spaces[0].shading.color_type = "OBJECT"
|
||||
return {"FINISHED"}
|
||||
|
||||
def preprocess_tasks(self):
|
||||
self.not_yet_started = set()
|
||||
self.started = set()
|
||||
self.completed = set()
|
||||
for rel in self.file.by_id(self.work_schedule).Controls or []:
|
||||
for related_object in rel.RelatedObjects:
|
||||
if related_object.is_a("IfcTask"):
|
||||
self.preprocess_task(related_object)
|
||||
|
||||
def preprocess_task(self, task):
|
||||
for rel in task.IsNestedBy or []:
|
||||
for related_object in rel.RelatedObjects:
|
||||
self.preprocess_task(related_object)
|
||||
start = helper.derive_date(task.id(), "ScheduleStart", is_earliest=True)
|
||||
finish = helper.derive_date(task.id(), "ScheduleFinish", is_latest=True)
|
||||
if not start or not finish:
|
||||
return
|
||||
products = [r.RelatingProduct.id() for r in task.HasAssignments or [] if r.is_a("IfcRelAssignsToProduct")]
|
||||
if not products:
|
||||
return
|
||||
if self.date < start:
|
||||
self.not_yet_started.update(products)
|
||||
elif self.date < finish:
|
||||
self.started.update(products)
|
||||
else:
|
||||
self.completed.update(products)
|
||||
|
||||
|
||||
class VisualiseWorkScheduleDateRange(bpy.types.Operator):
|
||||
bl_idname = "bim.visualise_work_schedule_date_range"
|
||||
bl_label = "Visualise Work Schedule Date Range"
|
||||
work_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
# for obj in bpy.context.visible_objects:
|
||||
# obj.select_set(False)
|
||||
# if obj.BIMObjectProperties.ifc_definition_id in related_products:
|
||||
# obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -107,6 +107,32 @@ def updateTaskTimeDateTime(self, context, startfinish):
|
||||
setattr(self, startfinish, canonicalise_time(startfinish_datetime))
|
||||
|
||||
|
||||
def updateVisualisationStart(self, context):
|
||||
updateVisualisationStartFinish(self, context, "visualisation_start")
|
||||
|
||||
def updateVisualisationFinish(self, context):
|
||||
updateVisualisationStartFinish(self, context, "visualisation_finish")
|
||||
|
||||
def updateVisualisationStartFinish(self, context, startfinish):
|
||||
def canonicalise_time(time):
|
||||
if not time:
|
||||
return "-"
|
||||
return time.strftime("%d/%m/%y")
|
||||
|
||||
startfinish_value = getattr(self, startfinish)
|
||||
try:
|
||||
startfinish_datetime = parser.isoparse(startfinish_value)
|
||||
except:
|
||||
try:
|
||||
startfinish_datetime = parser.parse(startfinish_value, dayfirst=True, fuzzy=True)
|
||||
except:
|
||||
setattr(self, startfinish, "-")
|
||||
return
|
||||
canonical_value = canonicalise_time(startfinish_datetime)
|
||||
if startfinish_value != canonical_value:
|
||||
setattr(self, startfinish, canonical_value)
|
||||
|
||||
|
||||
workschedule_enum = []
|
||||
|
||||
|
||||
@@ -159,6 +185,7 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
active_task_index: IntProperty(name="Active Task Index")
|
||||
active_task_id: IntProperty(name="Active Task Id")
|
||||
task_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||
should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False)
|
||||
should_show_times: BoolProperty(name="Should Show Times", default=False)
|
||||
active_task_time_id: IntProperty(name="Active Task Id")
|
||||
task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute)
|
||||
@@ -168,6 +195,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)
|
||||
|
||||
|
||||
class BIMTaskTreeProperties(PropertyGroup):
|
||||
|
||||
@@ -109,6 +109,7 @@ class BIM_PT_work_schedules(Panel):
|
||||
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
|
||||
elif self.props.editing_type == "TASKS":
|
||||
row.prop(self.props, "should_show_times", text="", icon="TIME")
|
||||
row.prop(self.props, "should_show_visualisation_ui", text="", icon="CAMERA_STEREO")
|
||||
row.operator("bim.generate_gantt_chart", text="", icon="NLA").work_schedule = work_schedule_id
|
||||
row.operator("bim.add_summary_task", text="", icon="ADD").work_schedule = work_schedule_id
|
||||
row.operator("bim.disable_editing_work_schedule", text="", icon="CANCEL")
|
||||
@@ -122,11 +123,21 @@ class BIM_PT_work_schedules(Panel):
|
||||
row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id
|
||||
|
||||
if self.props.active_work_schedule_id == work_schedule_id:
|
||||
if self.props.should_show_visualisation_ui:
|
||||
self.draw_visualisation_ui()
|
||||
if self.props.editing_type == "WORK_SCHEDULE":
|
||||
self.draw_editable_work_schedule_ui()
|
||||
elif self.props.editing_type == "TASKS":
|
||||
self.draw_editable_task_ui(work_schedule_id)
|
||||
|
||||
def draw_visualisation_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "visualisation_start", text="", icon="REW")
|
||||
row.prop(self.props, "visualisation_finish", text="", icon="FF")
|
||||
op = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF")
|
||||
op.work_schedule = self.props.active_work_schedule_id
|
||||
op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")
|
||||
|
||||
def draw_editable_work_schedule_ui(self):
|
||||
for attribute in self.props.work_schedule_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
|
||||
Reference in New Issue
Block a user