WIP you can now start a fresh project with partial editing support. See #1222.

This commit is contained in:
Dion Moult
2021-01-05 21:15:52 +11:00
parent f76d792a25
commit 113efa1206
16 changed files with 217 additions and 213 deletions
@@ -13,6 +13,7 @@ if bpy is not None:
import blenderbim.bim.module.covetool as module_covetool
import blenderbim.bim.module.geometry as module_geometry
import blenderbim.bim.module.model as module_model
import blenderbim.bim.module.project as module_project
import blenderbim.bim.module.spatial as module_spatial
import blenderbim.bim.module.unit as module_unit
from . import ui, prop, operator
@@ -92,7 +93,6 @@ if bpy is not None:
operator.GenerateGlobalId,
operator.AddMaterialAttribute,
operator.RemoveMaterialAttribute,
operator.QuickProjectSetup,
operator.SelectGlobalId,
operator.SelectAttribute,
operator.SelectPset,
@@ -320,6 +320,7 @@ if bpy is not None:
classes.extend(module_covetool.classes)
classes.extend(module_geometry.classes)
classes.extend(module_model.classes)
classes.extend(module_project.classes)
classes.extend(module_spatial.classes)
classes.extend(module_unit.classes)
@@ -361,6 +362,7 @@ if bpy is not None:
module_covetool.register()
module_geometry.register()
module_model.register()
module_project.register()
module_spatial.register()
module_unit.register()
bpy.app.handlers.depsgraph_update_pre.append(operator.depsgraph_update_pre_handler)
@@ -385,6 +387,7 @@ if bpy is not None:
bpy.types.SCENE_PT_unit.remove(ui.ifc_units)
module_unit.unregister()
module_spatial.unregister()
module_project.unregister()
module_model.unregister()
module_geometry.unregister()
module_covetool.unregister()
@@ -1414,15 +1414,16 @@ class IfcExporter:
self.file.wrapped_data.header.file_name.originating_system = "{} {}".format(
self.get_application_name(), self.get_application_version()
)
if self.owner_history:
if self.schema_version == "IFC2X3":
self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Id
else:
self.file.wrapped_data.header.file_name.authorization = (
self.owner_history.OwningUser.ThePerson.Identification
)
else:
self.file.wrapped_data.header.file_name.authorization = "Nobody"
# TODO: reimplement. See #1222.
#if self.owner_history:
# if self.schema_version == "IFC2X3":
# self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Id
# else:
# self.file.wrapped_data.header.file_name.authorization = (
# self.owner_history.OwningUser.ThePerson.Identification
# )
#else:
# self.file.wrapped_data.header.file_name.authorization = "Nobody"
def get_application_name(self):
return "BlenderBIM"
@@ -3463,6 +3464,7 @@ class IfcExporter:
return co * self.ifc_parser.unit_scale
def write_ifc_file(self):
self.set_header()
extension = self.ifc_export_settings.output_file.split(".")[-1]
if extension == "ifczip":
with tempfile.TemporaryDirectory() as unzipped_path:
@@ -7,22 +7,23 @@ from blenderbim.bim.module.aggregate.data import Data
class AssignObject(bpy.types.Operator):
bl_idname = "bim.assign_object"
bl_label = "Assign Object"
relating_object: bpy.props.StringProperty()
related_object: bpy.props.StringProperty()
def execute(self, context):
self.file = IfcStore.get_file()
obj = bpy.context.active_object
obj = bpy.data.objects.get(self.related_object) if self.related_object else bpy.context.active_object
props = obj.BIMObjectProperties
relating_object = props.relating_object
relating_object = bpy.data.objects.get(self.relating_object) if self.relating_object else props.relating_object
if not relating_object or not relating_object.BIMObjectProperties.ifc_definition_id:
return {"FINISHED"}
usecase = assign_object.Usecase(
assign_object.Usecase(
self.file,
{
"product": self.file.by_id(props.ifc_definition_id),
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
},
)
usecase.execute()
).execute()
Data.load(props.ifc_definition_id)
bpy.ops.bim.disable_editing_aggregate()
return {"FINISHED"}
@@ -18,8 +18,17 @@ class Usecase:
if not parent:
self.create_origin()
if self.settings["context"] == "Plan":
return self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin)
return self.file.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, self.origin)
context = self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin)
else:
context = self.file.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, self.origin)
project = self.file.by_type("IfcProject")[0]
if project.RepresentationContexts:
contexts = list(project.RepresentationContexts)
else:
contexts = []
contexts.append(context)
project.RepresentationContexts = contexts
return context
parent = parent[0]
return self.file.create_entity("IfcGeometricRepresentationSubContext", **{
"ContextIdentifier": self.settings["subcontext"],
@@ -8,18 +8,20 @@ from blenderbim.bim.module.context.data import Data
class AddSubcontext(bpy.types.Operator):
bl_idname = "bim.add_subcontext"
bl_label = "Add Subcontext"
context: bpy.props.StringProperty()
subcontext: bpy.props.StringProperty()
target_view: bpy.props.StringProperty()
def execute(self, context):
self.file = IfcStore.get_file()
usecase = add_context.Usecase(
add_context.Usecase(
self.file,
{
"context": bpy.context.scene.BIMProperties.available_contexts,
"subcontext": bpy.context.scene.BIMProperties.available_subcontexts,
"target_view": bpy.context.scene.BIMProperties.available_target_views,
"context": self.context or bpy.context.scene.BIMProperties.available_contexts,
"subcontext": self.subcontext or bpy.context.scene.BIMProperties.available_subcontexts,
"target_view": self.target_view or bpy.context.scene.BIMProperties.available_target_views,
},
)
result = usecase.execute()
).execute()
Data.load()
return {"FINISHED"}
@@ -10,6 +10,8 @@ class Usecase:
self.settings[key] = value
def execute(self):
if not hasattr(self.settings["product"], "ObjectPlacement"):
return
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
if not self.settings["product"].ObjectPlacement:
placement_rel_to = None
@@ -0,0 +1,15 @@
import bpy
from . import ui, operator
classes = (
operator.CreateProject,
ui.BIM_PT_project,
)
def register():
pass
def unregister():
pass
@@ -0,0 +1,25 @@
import datetime
import ifcopenshell
class Usecase:
def __init__(self, settings=None):
self.settings = {"version": "IFC4"}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
self.file = ifcopenshell.file(schema=self.settings["version"])
# TODO: add all metadata, pending bug #747
self.file.wrapped_data.header.file_name.name = "/dev/null" # Hehehe
self.file.wrapped_data.header.file_name.time_stamp = (
datetime.datetime.utcnow()
.replace(tzinfo=datetime.timezone.utc)
.astimezone()
.replace(microsecond=0)
.isoformat()
)
self.file.wrapped_data.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
self.file.wrapped_data.header.file_name.originating_system = "IfcOpenShell {}".format(ifcopenshell.version)
self.file.wrapped_data.header.file_name.authorization = "Nobody"
return self.file
@@ -0,0 +1,68 @@
import bpy
import ifcopenshell
import blenderbim.bim.module.project.create_file as create_file
import blenderbim.bim.module.context.add_context as add_context
import blenderbim.bim.module.root.create_product as create_product
import blenderbim.bim.module.aggregate.assign_object as assign_object
import bpy
from blenderbim.bim.ifc import IfcStore
# from blenderbim.bim.module.project.data import Data
class CreateProject(bpy.types.Operator):
bl_idname = "bim.create_project"
bl_label = "Create Project"
def execute(self, context):
self.file = IfcStore.get_file()
if self.file:
return {"FINISHED"}
IfcStore.file = create_file.Usecase({"version": bpy.context.scene.BIMProperties.export_schema}).execute()
self.file = IfcStore.get_file()
project = bpy.data.collections.new("My Project")
site = bpy.data.collections.new("My Site")
building = bpy.data.collections.new("My Building")
building_storey = bpy.data.collections.new("Ground Floor")
project_obj = bpy.data.objects.new("My Project", None)
site_obj = bpy.data.objects.new("My Site", None)
building_obj = bpy.data.objects.new("My Building", None)
building_storey_obj = bpy.data.objects.new("Ground Floor", None)
bpy.context.scene.collection.children.link(project)
project.children.link(site)
site.children.link(building)
building.children.link(building_storey)
project.objects.link(project_obj)
site.objects.link(site_obj)
building.objects.link(building_obj)
building_storey.objects.link(building_storey_obj)
bpy.ops.bim.assign_class(obj=project_obj.name, ifc_class="IfcProject")
bpy.ops.bim.assign_unit()
bpy.ops.bim.add_subcontext(context="Model")
bpy.ops.bim.add_subcontext(context="Model", subcontext="Body", target_view="MODEL_VIEW")
bpy.ops.bim.add_subcontext(context="Model", subcontext="Box", target_view="MODEL_VIEW")
bpy.ops.bim.add_subcontext(context="Plan")
bpy.ops.bim.add_subcontext(context="Plan", subcontext="Annotation", target_view="PLAN_VIEW")
bpy.ops.bim.assign_class(obj=site_obj.name, ifc_class="IfcSite")
bpy.ops.bim.assign_class(obj=building_obj.name, ifc_class="IfcBuilding")
bpy.ops.bim.assign_class(obj=building_storey_obj.name, ifc_class="IfcBuildingStorey")
bpy.ops.bim.assign_object(related_object=site_obj.name, relating_object=project_obj.name)
bpy.ops.bim.assign_object(related_object=building_obj.name, relating_object=site_obj.name)
bpy.ops.bim.assign_object(related_object=building_storey_obj.name, relating_object=building_obj.name)
# Data.load()
return {"FINISHED"}
def assign_object(self, product, relating_object):
assign_object.Usecase(
self.file,
{
"product": product,
"relating_object": relating_object,
},
).execute()
@@ -0,0 +1,31 @@
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
class BIM_PT_project(Panel):
bl_label = "IFC Project"
bl_idname = "BIM_PT_project"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
self.layout.use_property_decorate = False
self.layout.use_property_split = True
self.file = IfcStore.get_file()
props = context.scene.BIMProperties
if self.file:
pass
else:
row = self.layout.row()
row.prop(props, "export_schema")
row = self.layout.row()
row.prop(context.scene.unit_settings, "system")
row = self.layout.row()
row.prop(context.scene.unit_settings, "length_unit")
row = self.layout.row()
row.prop(props, "area_unit", text="Area Unit")
row = self.layout.row()
row.prop(props, "volume_unit", text="Volume Unit")
row = self.layout.row()
row.operator("bim.create_project")
@@ -60,15 +60,14 @@ class ReassignClass(bpy.types.Operator):
predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type
if predefined_type == "USERDEFINED":
predefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type
usecase = reassign_class.Usecase(
product = reassign_class.Usecase(
self.file,
{
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
"predefined_type": predefined_type,
},
)
product = usecase.execute()
).execute()
obj.name = "{}/{}".format(product.is_a(), "/".join(obj.name.split("/")[1:]))
obj.BIMObjectProperties.ifc_definition_id = int(product.id())
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = False
@@ -78,48 +77,51 @@ class ReassignClass(bpy.types.Operator):
class AssignClass(bpy.types.Operator):
bl_idname = "bim.assign_class"
bl_label = "Assign IFC Class"
object_name: bpy.props.StringProperty()
obj: bpy.props.StringProperty()
ifc_class: bpy.props.StringProperty()
predefined_type: bpy.props.StringProperty()
userdefined_type: bpy.props.StringProperty()
def execute(self, context):
objects = [bpy.data.objects.get(self.object_name)] if self.object_name else bpy.context.selected_objects
objects = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
self.file = IfcStore.get_file()
for obj in objects:
if obj.BIMObjectProperties.ifc_definition_id:
continue
predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type
if predefined_type == "USERDEFINED":
predefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type
usecase = create_product.Usecase(
if self.predefined_type == "USERDEFINED":
predefined_type = self.ifc_userdefined_type
elif self.predefined_type == "":
predefined_type = None
else:
predefined_type = self.predefined_type
product = create_product.Usecase(
self.file,
{
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
"ifc_class": self.ifc_class,
"predefined_type": predefined_type,
"name": obj.name,
},
)
product = usecase.execute()
).execute()
usecase = add_object_placement.Usecase(
add_object_placement.Usecase(
self.file,
{
"product": product,
"matrix": np.array(obj.matrix_world),
},
)
result = usecase.execute()
).execute()
if obj.data:
usecase = add_representation.Usecase(
representation = add_representation.Usecase(
self.file,
{
"context": self.file.by_id(int(bpy.context.scene.BIMProperties.contexts)),
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
},
)
representation = usecase.execute()
).execute()
usecase = assign_styles.Usecase(
assign_styles.Usecase(
self.file,
{
"shape_representation": representation,
@@ -129,13 +131,11 @@ class AssignClass(bpy.types.Operator):
if s.material
],
},
)
usecase.execute()
).execute()
usecase = assign_representation.Usecase(
assign_representation.Usecase(
self.file, {"product": product, "representation": representation}
)
usecase.execute()
).execute()
relating_structure = None
for collection in obj.users_collection:
@@ -146,16 +146,15 @@ class AssignClass(bpy.types.Operator):
break
if relating_structure:
usecase = assign_container.Usecase(
assign_container.Usecase(
self.file,
{
"product": product,
"relating_structure": relating_structure,
},
)
usecase.execute()
).execute()
obj.name = "{}/{}".format(bpy.context.scene.BIMProperties.ifc_class, obj.name)
obj.name = "{}/{}".format(product.is_a(), obj.name)
obj.BIMObjectProperties.ifc_definition_id = int(product.id())
if bpy.context.scene.BIMProperties.ifc_product == "IfcElementType":
self.place_in_types_collection(obj)
@@ -1,6 +1,7 @@
import bpy
from bpy.types import Panel
from blenderbim.bim.module.root.data import Data
from blenderbim.bim.ifc import IfcStore
class BIM_PT_class(Panel):
bl_label = "IFC Class"
@@ -9,6 +10,10 @@ class BIM_PT_class(Panel):
bl_region_type = "WINDOW"
bl_context = "object"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
props = context.active_object.BIMObjectProperties
if props.ifc_definition_id:
@@ -35,7 +40,10 @@ class BIM_PT_class(Panel):
self.draw_class_dropdowns()
row = self.layout.row(align=True)
op = row.operator("bim.assign_class")
op.object_name = context.active_object.name
op.obj = context.active_object.name
op.ifc_class = bpy.context.scene.BIMProperties.ifc_class
op.predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type
op.userdefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type
def draw_class_dropdowns(self):
props = bpy.context.scene.BIMProperties
@@ -461,33 +461,6 @@ class SelectAudited(bpy.types.Operator):
return word[0] in ["0", "1", "2", "3"] and len(word) == 22
class QuickProjectSetup(bpy.types.Operator):
bl_idname = "bim.quick_project_setup"
bl_label = "Quick Project Setup"
def execute(self, context):
project = bpy.data.collections.new("IfcProject/My Project")
site = bpy.data.collections.new("IfcSite/My Site")
building = bpy.data.collections.new("IfcBuilding/My Building")
building_storey = bpy.data.collections.new("IfcBuildingStorey/Ground Floor")
project_obj = bpy.data.objects.new("IfcProject/My Project", None)
site_obj = bpy.data.objects.new("IfcSite/My Site", None)
building_obj = bpy.data.objects.new("IfcBuilding/My Building", None)
building_storey_obj = bpy.data.objects.new("IfcBuildingStorey/Ground Floor", None)
bpy.context.scene.collection.children.link(project)
project.children.link(site)
site.children.link(building)
building.children.link(building_storey)
project.objects.link(project_obj)
site.objects.link(site_obj)
building.objects.link(building_obj)
building_storey.objects.link(building_storey_obj)
return {"FINISHED"}
class AddQto(bpy.types.Operator):
bl_idname = "bim.add_qto"
bl_label = "Add Qto"
@@ -14,7 +14,6 @@ class IfcSchema:
self.data_dir = Path(cwd).joinpath("data") # TODO: make configurable
# TODO: Make it less troublesome
self.products = [
"IfcContext",
"IfcElement",
"IfcSpatialElement",
"IfcGroup",
@@ -1,114 +0,0 @@
{
"IfcProject": {
"is_abstract": false,
"parent": "IfcContext",
"attributes": [
{
"name": "GlobalId",
"type": "IfcGloballyUniqueId",
"is_enum": false,
"enum_values": []
},
{
"name": "Name",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Description",
"type": "IfcText",
"is_enum": false,
"enum_values": []
},
{
"name": "ObjectType",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "LongName",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Phase",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
}
],
"complex_attributes": [
{
"name": "OwnerHistory",
"type": "IfcOwnerHistory",
"is_select": false,
"select_types": []
},
{
"name": "UnitsInContext",
"type": "IfcUnitAssignment",
"is_select": false,
"select_types": []
}
]
},
"IfcProjectLibrary": {
"is_abstract": false,
"parent": "IfcContext",
"attributes": [
{
"name": "GlobalId",
"type": "IfcGloballyUniqueId",
"is_enum": false,
"enum_values": []
},
{
"name": "Name",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Description",
"type": "IfcText",
"is_enum": false,
"enum_values": []
},
{
"name": "ObjectType",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "LongName",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
},
{
"name": "Phase",
"type": "IfcLabel",
"is_enum": false,
"enum_values": []
}
],
"complex_attributes": [
{
"name": "OwnerHistory",
"type": "IfcOwnerHistory",
"is_select": false,
"select_types": []
},
{
"name": "UnitsInContext",
"type": "IfcUnitAssignment",
"is_select": false,
"select_types": []
}
]
}
}
-19
View File
@@ -1369,9 +1369,6 @@ class BIM_PT_bim(Panel):
layout.label(text="System Setup:")
row = layout.row()
row.operator("bim.quick_project_setup")
row = layout.row(align=True)
row.prop(bim_properties, "schema_dir")
row.operator("bim.select_schema_dir", icon="FILE_FOLDER", text="")
@@ -1391,22 +1388,6 @@ class BIM_PT_bim(Panel):
layout.label(text="IFC Categorisation:")
row = layout.row()
row.prop(bim_properties, "ifc_product")
row = layout.row()
row.prop(bim_properties, "ifc_class")
if bim_properties.ifc_predefined_type:
row = layout.row()
row.prop(bim_properties, "ifc_predefined_type")
if bim_properties.ifc_predefined_type == "USERDEFINED":
row = layout.row()
row.prop(bim_properties, "ifc_userdefined_type")
row = layout.row(align=True)
op = row.operator("bim.assign_class")
op.object_name = ""
op = row.operator("bim.unassign_class", icon="X", text="")
op.object_name = ""
row = layout.row(align=True)
row.operator("bim.select_class")
row.operator("bim.select_type")