mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-23 21:38:51 +00:00
You can now generate construction sequence animations to visualise within a date range
This commit is contained in:
@@ -1462,8 +1462,86 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
# for obj in bpy.context.visible_objects:
|
self.props = context.scene.BIMWorkScheduleProperties
|
||||||
# obj.select_set(False)
|
self.start = parser.parse(self.props.visualisation_start, dayfirst=True, fuzzy=True)
|
||||||
# if obj.BIMObjectProperties.ifc_definition_id in related_products:
|
self.finish = parser.parse(self.props.visualisation_finish, dayfirst=True, fuzzy=True)
|
||||||
# obj.select_set(True)
|
self.duration = self.finish - self.start
|
||||||
|
self.start_frame = 1
|
||||||
|
self.total_frames = self.calculate_total_frames()
|
||||||
|
self.preprocess_tasks()
|
||||||
|
for obj in bpy.data.objects:
|
||||||
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||||
|
continue
|
||||||
|
product_frames = self.product_frames.get(obj.BIMObjectProperties.ifc_definition_id)
|
||||||
|
if not product_frames:
|
||||||
|
continue
|
||||||
|
obj.hide_viewport = True
|
||||||
|
obj.keyframe_insert(data_path="hide_viewport", frame=self.start_frame)
|
||||||
|
obj.hide_viewport = False
|
||||||
|
obj.color = (0.0, 1.0, 0.0, 1)
|
||||||
|
obj.keyframe_insert(data_path="hide_viewport", frame=product_frames["STARTED"])
|
||||||
|
obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"])
|
||||||
|
obj.color = (1.0, 1.0, 1.0, 1)
|
||||||
|
obj.keyframe_insert(data_path="color", frame=product_frames["COMPLETED"])
|
||||||
|
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
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def calculate_total_frames(self):
|
||||||
|
if self.props.speed_types == "FRAME_SPEED":
|
||||||
|
return self.calculate_using_frames(
|
||||||
|
self.start,
|
||||||
|
self.finish,
|
||||||
|
self.props.speed_animation_frames,
|
||||||
|
isodate.parse_duration(self.props.speed_real_duration),
|
||||||
|
)
|
||||||
|
elif self.props.speed_types == "DURATION_SPEED":
|
||||||
|
return self.calculate_using_duration(
|
||||||
|
self.start,
|
||||||
|
self.finish,
|
||||||
|
bpy.context.scene.render.fps,
|
||||||
|
isodate.parse_duration(self.props.speed_animation_duration),
|
||||||
|
isodate.parse_duration(self.props.speed_real_duration),
|
||||||
|
)
|
||||||
|
elif self.props.speed_types == "MULTIPLIER_SPEED":
|
||||||
|
return self.calculate_using_multiplier(
|
||||||
|
self.start,
|
||||||
|
self.finish,
|
||||||
|
bpy.context.scene.render.fps,
|
||||||
|
isodate.parse_duration(self.props.speed_animation_duration),
|
||||||
|
self.props.speed_multiplier,
|
||||||
|
)
|
||||||
|
|
||||||
|
def calculate_using_multiplier(self, start, finish, fps, multiplier):
|
||||||
|
animation_time = (finish - start) / multiplier
|
||||||
|
return animation_time.total_seconds() * fps
|
||||||
|
|
||||||
|
def calculate_using_duration(self, start, finish, fps, animation_duration, real_duration):
|
||||||
|
return self.calculate_using_multiplier(start, finish, fps, real_duration / animation_duration)
|
||||||
|
|
||||||
|
def calculate_using_frames(self, start, finish, animation_frames, real_duration):
|
||||||
|
return ((finish - start) / real_duration) * animation_frames
|
||||||
|
|
||||||
|
def preprocess_tasks(self):
|
||||||
|
self.product_frames = {}
|
||||||
|
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
|
||||||
|
product_ids = [r.RelatingProduct.id() for r in task.HasAssignments or [] if r.is_a("IfcRelAssignsToProduct")]
|
||||||
|
for product_id in product_ids:
|
||||||
|
self.product_frames[product_id] = {
|
||||||
|
"STARTED": round(self.start_frame + (((start - self.start) / self.duration) * self.total_frames)),
|
||||||
|
"COMPLETED": round(self.start_frame + (((finish - self.start) / self.duration) * self.total_frames)),
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,9 +110,11 @@ def updateTaskTimeDateTime(self, context, startfinish):
|
|||||||
def updateVisualisationStart(self, context):
|
def updateVisualisationStart(self, context):
|
||||||
updateVisualisationStartFinish(self, context, "visualisation_start")
|
updateVisualisationStartFinish(self, context, "visualisation_start")
|
||||||
|
|
||||||
|
|
||||||
def updateVisualisationFinish(self, context):
|
def updateVisualisationFinish(self, context):
|
||||||
updateVisualisationStartFinish(self, context, "visualisation_finish")
|
updateVisualisationStartFinish(self, context, "visualisation_finish")
|
||||||
|
|
||||||
|
|
||||||
def updateVisualisationStartFinish(self, context, startfinish):
|
def updateVisualisationStartFinish(self, context, startfinish):
|
||||||
def canonicalise_time(time):
|
def canonicalise_time(time):
|
||||||
if not time:
|
if not time:
|
||||||
@@ -197,6 +199,19 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
|||||||
time_lag_attributes: CollectionProperty(name="Time Lag Attributes", type=Attribute)
|
time_lag_attributes: CollectionProperty(name="Time Lag Attributes", type=Attribute)
|
||||||
visualisation_start: StringProperty(name="Visualisation Start", update=updateVisualisationStart)
|
visualisation_start: StringProperty(name="Visualisation Start", update=updateVisualisationStart)
|
||||||
visualisation_finish: StringProperty(name="Visualisation Finish", update=updateVisualisationFinish)
|
visualisation_finish: StringProperty(name="Visualisation Finish", update=updateVisualisationFinish)
|
||||||
|
speed_multiplier: FloatProperty(name="Speed Multiplier")
|
||||||
|
speed_animation_duration: StringProperty(name="Speed Animation Duration", default="PT1S")
|
||||||
|
speed_animation_frames: IntProperty(name="Speed Animation Frames", default=24)
|
||||||
|
speed_real_duration: StringProperty(name="Speed Real Duration", default="P1W")
|
||||||
|
speed_types: EnumProperty(
|
||||||
|
items=[
|
||||||
|
("FRAME_SPEED", "Frame-based", "e.g. 25 frames = 1 real week"),
|
||||||
|
("DURATION_SPEED", "Duration-based", "e.g. 1 video second = 1 real week"),
|
||||||
|
("MULTIPLIER_SPEED", "Multiplier", "e.g. 1000 x real life speed"),
|
||||||
|
],
|
||||||
|
name="Speed Type",
|
||||||
|
default="FRAME_SPEED",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BIMTaskTreeProperties(PropertyGroup):
|
class BIMTaskTreeProperties(PropertyGroup):
|
||||||
@@ -227,16 +242,19 @@ class BIMWorkCalendarProperties(PropertyGroup):
|
|||||||
position: IntProperty(name="Position")
|
position: IntProperty(name="Position")
|
||||||
interval: IntProperty(name="Recurrence Interval")
|
interval: IntProperty(name="Recurrence Interval")
|
||||||
occurrences: IntProperty(name="Occurs N Times")
|
occurrences: IntProperty(name="Occurs N Times")
|
||||||
recurrence_types: EnumProperty(items=[
|
recurrence_types: EnumProperty(
|
||||||
("DAILY", "Daily", "e.g. Every day"),
|
items=[
|
||||||
("WEEKLY", "Weekly", "e.g. Every Friday"),
|
("DAILY", "Daily", "e.g. Every day"),
|
||||||
("MONTHLY_BY_DAY_OF_MONTH", "Monthly on Specified Date", "e.g. Every 2nd of each Month"),
|
("WEEKLY", "Weekly", "e.g. Every Friday"),
|
||||||
("MONTHLY_BY_POSITION", "Monthly on Specified Weekday", "e.g. Every 1st Friday of each Month"),
|
("MONTHLY_BY_DAY_OF_MONTH", "Monthly on Specified Date", "e.g. Every 2nd of each Month"),
|
||||||
# https://forums.buildingsmart.org/t/what-does-by-day-count-and-by-weekday-count-mean-in-ifcrecurrencetypeenum/3571
|
("MONTHLY_BY_POSITION", "Monthly on Specified Weekday", "e.g. Every 1st Friday of each Month"),
|
||||||
# ("BY_DAY_COUNT", "", ""),
|
# https://forums.buildingsmart.org/t/what-does-by-day-count-and-by-weekday-count-mean-in-ifcrecurrencetypeenum/3571
|
||||||
# ("BY_WEEKDAY_COUNT", "", ""),
|
# ("BY_DAY_COUNT", "", ""),
|
||||||
("YEARLY_BY_DAY_OF_MONTH", "Yearly on Specified Date", "e.g. Every 2nd of October"),
|
# ("BY_WEEKDAY_COUNT", "", ""),
|
||||||
("YEARLY_BY_POSITION", "Yearly on Specified Weekday", "e.g. Every 1st Friday of October"),
|
("YEARLY_BY_DAY_OF_MONTH", "Yearly on Specified Date", "e.g. Every 2nd of October"),
|
||||||
], name="Recurrence Types")
|
("YEARLY_BY_POSITION", "Yearly on Specified Weekday", "e.g. Every 1st Friday of October"),
|
||||||
|
],
|
||||||
|
name="Recurrence Types",
|
||||||
|
)
|
||||||
start_time: StringProperty(name="Start Time")
|
start_time: StringProperty(name="Start Time")
|
||||||
end_time: StringProperty(name="End Time")
|
end_time: StringProperty(name="End Time")
|
||||||
|
|||||||
@@ -137,6 +137,18 @@ class BIM_PT_work_schedules(Panel):
|
|||||||
op = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF")
|
op = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF")
|
||||||
op.work_schedule = self.props.active_work_schedule_id
|
op.work_schedule = self.props.active_work_schedule_id
|
||||||
op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")
|
op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")
|
||||||
|
op.work_schedule = self.props.active_work_schedule_id
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "speed_types", text="")
|
||||||
|
if self.props.speed_types == "FRAME_SPEED":
|
||||||
|
row.prop(self.props, "speed_animation_frames", text="")
|
||||||
|
row.prop(self.props, "speed_real_duration", text="")
|
||||||
|
elif self.props.speed_types == "DURATION_SPEED":
|
||||||
|
row.prop(self.props, "speed_animation_duration", text="")
|
||||||
|
row.prop(self.props, "speed_real_duration", text="")
|
||||||
|
elif self.props.speed_types == "MULTIPLIER_SPEED":
|
||||||
|
row.prop(self.props, "speed_multiplier", text="")
|
||||||
|
|
||||||
def draw_editable_work_schedule_ui(self):
|
def draw_editable_work_schedule_ui(self):
|
||||||
for attribute in self.props.work_schedule_attributes:
|
for attribute in self.props.work_schedule_attributes:
|
||||||
|
|||||||
Reference in New Issue
Block a user