You can now import an IFC work schedule from a P6 XML export

This commit is contained in:
Dion Moult
2021-04-22 15:44:58 +10:00
parent dca2e58586
commit ee0f7f1677
4 changed files with 143 additions and 129 deletions
@@ -41,6 +41,7 @@ classes = (
operator.AssignProduct, operator.AssignProduct,
operator.UnassignProduct, operator.UnassignProduct,
operator.GenerateGanttChart, operator.GenerateGanttChart,
operator.ImportP6,
prop.WorkPlan, prop.WorkPlan,
prop.BIMWorkPlanProperties, prop.BIMWorkPlanProperties,
prop.Task, prop.Task,
@@ -56,13 +57,19 @@ classes = (
) )
def menu_func_import(self, context):
self.layout.operator(operator.ImportP6.bl_idname, text="P6 (.xml)")
def register(): def register():
bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties) bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties)
bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties) bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties)
bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties) bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
def unregister(): def unregister():
del bpy.types.Scene.BIMWorkPlanProperties del bpy.types.Scene.BIMWorkPlanProperties
del bpy.types.Scene.BIMWorkScheduleProperties del bpy.types.Scene.BIMWorkScheduleProperties
del bpy.types.Scene.BIMWorkCalendarProperties del bpy.types.Scene.BIMWorkCalendarProperties
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
@@ -1,12 +1,14 @@
import os import os
import bpy import bpy
import json import json
import time
import pystache import pystache
import webbrowser import webbrowser
import ifcopenshell.api import ifcopenshell.api
from datetime import datetime from datetime import datetime
from dateutil import parser from dateutil import parser
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper
from ifcopenshell.api.sequence.data import Data from ifcopenshell.api.sequence.data import Data
@@ -808,3 +810,23 @@ class DisableEditingWorkCalendar(bpy.types.Operator):
def execute(self, context): def execute(self, context):
context.scene.BIMWorkCalendarProperties.active_work_calendar_id = 0 context.scene.BIMWorkCalendarProperties.active_work_calendar_id = 0
return {"FINISHED"} return {"FINISHED"}
class ImportP6(bpy.types.Operator, ImportHelper):
bl_idname = "import_p6.bim"
bl_label = "Import P6"
filename_ext = ".xml"
filter_glob: bpy.props.StringProperty(default="*.xml", options={"HIDDEN"})
def execute(self, context):
from ifcp6.p62ifc import P62Ifc
self.file = IfcStore.get_file()
start = time.time()
p62ifc = P62Ifc()
p62ifc.xml = self.filepath
p62ifc.file = self.file
p62ifc.work_plan = self.file.by_type("IfcWorkPlan")[0]
p62ifc.execute()
Data.load(IfcStore.get_file())
print("Import finished in {:.2f} seconds".format(time.time() - start))
return {"FINISHED"}
-129
View File
@@ -1,129 +0,0 @@
import ifcopenshell
import ifcopenshell.util.date
import xml.etree.ElementTree as ET
class P6ToIfc:
def __init__(self):
self.project = {}
self.wbs = {}
def execute(self):
self.parse_xml()
self.create_ifc()
def parse_xml(self):
tree = ET.parse("p6.xml")
ns = {"pr": "http://xmlns.oracle.com/Primavera/P6/V19.12/API/BusinessObjects"}
root = tree.getroot()
project = root.find("pr:Project", ns)
self.project["Name"] = project.find("pr:Name", ns).text
for wbs in project.findall("pr:WBS", ns):
self.wbs[wbs.find("pr:ObjectId", ns).text] = {
"Name": wbs.find("pr:Name", ns).text,
"ParentObjectId": wbs.find("pr:ParentObjectId", ns).text,
"ifc": None,
"rel": None,
"activities": [],
}
for activity in project.findall("pr:Activity", ns):
self.wbs[activity.find("pr:WBSObjectId", ns).text]["activities"].append(
{
"Name": activity.find("pr:Name", ns).text,
"Identification": activity.find("pr:Id", ns).text,
"StartDate": activity.find("pr:StartDate", ns).text,
"FinishDate": activity.find("pr:FinishDate", ns).text,
"ifc": None,
}
)
def get_wbs(self, wbs):
return {"Name": wbs.find("pr:Name", ns).text, "subtasks": []}
def create_ifc(self):
self.file = ifcopenshell.file(schema="IFC4")
# self.file = ifcopenshell.file(schema="IFC2X3")
self.root = self.file.create_entity(
"IfcTask", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.project["Name"]}
)
self.root_rel = self.create_rel_nests(self.root)
for wbs in self.wbs.values():
wbs["ifc"] = self.file.create_entity(
"IfcTask", **{"GlobalId": ifcopenshell.guid.new(), "Name": wbs["Name"]}
)
if wbs["ParentObjectId"]:
parent_wbs = self.wbs[wbs["ParentObjectId"]]
if not parent_wbs["rel"]:
parent_wbs["rel"] = self.create_rel_nests(parent_wbs["ifc"])
rel = parent_wbs["rel"]
else:
rel = self.root_rel
self.append_to_rel(rel, wbs["ifc"])
for activity in wbs["activities"]:
if not wbs["rel"]:
wbs["rel"] = self.create_rel_nests(wbs["ifc"])
if self.file.schema == "IFC2X3":
activity["TimeForTask"] = self.file.create_entity(
"IfcScheduleTimeControl",
**{
"ScheduleStart": self.file.create_entity(
"IfcCalendarDate",
**ifcopenshell.util.date.datetime2ifc(activity["StartDate"], "IfcCalendarDate")
),
"ScheduleFinish": self.file.create_entity(
"IfcCalendarDate",
**ifcopenshell.util.date.datetime2ifc(activity["FinishDate"], "IfcCalendarDate")
),
}
)
else:
activity["TaskTime"] = self.file.create_entity(
"IfcTaskTime",
**{"ScheduleStart": activity["StartDate"], "ScheduleFinish": activity["FinishDate"]}
)
is_milestone = activity["StartDate"] == activity["FinishDate"]
activity["ifc"] = self.file.create_entity(
"IfcTask",
**{
"GlobalId": ifcopenshell.guid.new(),
"Name": activity["Name"],
"Identification": activity["Identification"],
"IsMilestone": is_milestone,
}
)
if self.file.schema == "IFC2X3":
# Invalid, but reading the IFC2X3 docs gives me a headache
self.file.create_entity(
"IfcRelAssignsTasks",
**{
"GlobalId": ifcopenshell.guid.new(),
"RelatedObjects": [activity["ifc"]],
"TimeForTask": activity["TimeForTask"],
}
)
else:
activity["ifc"].TaskTime = activity["TaskTime"]
self.append_to_rel(wbs["rel"], activity["ifc"])
self.file.write("p6.ifc")
def create_rel_nests(self, relating_object):
return self.file.create_entity(
"IfcRelNests", **{"GlobalId": ifcopenshell.guid.new(), "RelatingObject": relating_object}
)
def append_to_rel(self, rel, element):
related_objects = list(rel.RelatedObjects or [])
related_objects.append(element)
rel.RelatedObjects = related_objects
p6_to_ifc = P6ToIfc()
p6_to_ifc.execute()
+114
View File
@@ -0,0 +1,114 @@
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.date
import xml.etree.ElementTree as ET
from datetime import datetime
class P62Ifc:
def __init__(self):
self.xml = None
self.file = None
self.work_plan = None
self.project = {}
self.wbs = {}
self.activity = {}
def execute(self):
self.parse_xml()
self.create_ifc()
def parse_xml(self):
tree = ET.parse(self.xml)
ns = {"pr": "http://xmlns.oracle.com/Primavera/P6/V19.12/API/BusinessObjects"}
root = tree.getroot()
project = root.find("pr:Project", ns)
self.project["Name"] = project.find("pr:Name", ns).text
for wbs in project.findall("pr:WBS", ns):
self.wbs[wbs.find("pr:ObjectId", ns).text] = {
"Name": wbs.find("pr:Name", ns).text,
"Code": wbs.find("pr:Code", ns).text,
"ParentObjectId": wbs.find("pr:ParentObjectId", ns).text,
"ifc": None,
"rel": None,
"activities": [],
}
for activity in project.findall("pr:Activity", ns):
self.wbs[activity.find("pr:WBSObjectId", ns).text]["activities"].append(
{
"Name": activity.find("pr:Name", ns).text,
"Identification": activity.find("pr:Id", ns).text,
"StartDate": datetime.fromisoformat(activity.find("pr:StartDate", ns).text),
"FinishDate": datetime.fromisoformat(activity.find("pr:FinishDate", ns).text),
"Status": activity.find("pr:Status", ns).text,
"ifc": None,
}
)
def get_wbs(self, wbs):
return {"Name": wbs.find("pr:Name", ns).text, "subtasks": []}
def create_ifc(self):
if not self.file:
self.file = self.create_boilerplate_ifc()
work_schedule = self.create_work_schedule()
self.create_tasks(work_schedule)
def create_work_schedule(self):
return ifcopenshell.api.run(
"sequence.add_work_schedule", self.file, name=self.project["Name"], work_plan=self.work_plan
)
def create_tasks(self, work_schedule):
for wbs in self.wbs.values():
self.create_task_from_wbs(wbs, work_schedule)
def create_task_from_wbs(self, wbs, work_schedule):
wbs["ifc"] = ifcopenshell.api.run(
"sequence.add_task",
self.file,
work_schedule=None if wbs["ParentObjectId"] else work_schedule,
parent_task=self.wbs[wbs["ParentObjectId"]]["ifc"] if wbs["ParentObjectId"] else None,
)
ifcopenshell.api.run(
"sequence.edit_task",
self.file,
task=wbs["ifc"],
attributes={"Name": wbs["Name"], "Identification": wbs["Code"]},
)
for activity in wbs["activities"]:
self.create_task_from_activity(activity, wbs, work_schedule)
def create_task_from_activity(self, activity, wbs, work_schedule):
activity["ifc"] = ifcopenshell.api.run(
"sequence.add_task",
self.file,
parent_task=wbs["ifc"],
)
ifcopenshell.api.run(
"sequence.edit_task",
self.file,
task=activity["ifc"],
attributes={
"Name": activity["Name"],
"Identification": activity["Identification"],
"Status": activity["Status"],
"IsMilestone": activity["StartDate"] == activity["FinishDate"],
},
)
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=activity["ifc"])
ifcopenshell.api.run(
"sequence.edit_task_time",
self.file,
task_time=task_time,
attributes={
"ScheduleStart": activity["StartDate"],
"ScheduleFinish": activity["FinishDate"],
},
)
def create_boilerplate_ifc(self):
self.file = ifcopenshell.file(schema="IFC4")
self.work_plan = self.file.create_entity("IfcWorkPlan")