mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 06:18:09 +00:00
274 lines
11 KiB
Python
274 lines
11 KiB
Python
import bpy
|
|
import json
|
|
import addon_utils
|
|
import ifcopenshell.api.owner.settings
|
|
from bpy.app.handlers import persistent
|
|
from blenderbim.bim.ifc import IfcStore
|
|
from ifcopenshell.api.attribute.data import Data as AttributeData
|
|
from ifcopenshell.api.type.data import Data as TypeData
|
|
|
|
|
|
global_subscription_owner = object()
|
|
|
|
|
|
def mode_callback(obj, data):
|
|
for obj in bpy.context.selected_objects + [bpy.context.active_object]:
|
|
if (
|
|
obj.mode != "EDIT"
|
|
or not obj.data
|
|
or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve))
|
|
or not obj.BIMObjectProperties.ifc_definition_id
|
|
or not bpy.context.scene.BIMProjectProperties.is_authoring
|
|
):
|
|
return
|
|
if obj.data.BIMMeshProperties.ifc_definition_id:
|
|
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
|
if representation.RepresentationType in ["Tessellation", "Brep", "Annotation2D"]:
|
|
IfcStore.edited_objs.add(obj)
|
|
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
|
|
IfcStore.edited_objs.add(obj)
|
|
|
|
|
|
def name_callback(obj, data):
|
|
# Blender material names are up to 63 UTF-8 bytes
|
|
if not obj.BIMObjectProperties.ifc_definition_id or "/" not in obj.name or len(bytes(obj.name, "utf-8")) >= 63:
|
|
return
|
|
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
|
if not element.is_a("IfcRoot"):
|
|
return
|
|
if element.is_a("IfcSpatialStructureElement") or (hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy):
|
|
collection = obj.users_collection[0]
|
|
collection.name = obj.name
|
|
if element.is_a("IfcGrid"):
|
|
axis_obj = IfcStore.id_map[element.UAxes[0].id()]
|
|
axis_collection = axis_obj.users_collection[0]
|
|
grid_collection = None
|
|
for collection in bpy.data.collections:
|
|
if axis_collection.name in collection.children.keys():
|
|
grid_collection = collection
|
|
break
|
|
if grid_collection:
|
|
grid_collection.name = obj.name
|
|
if element.is_a("IfcTypeProduct"):
|
|
TypeData.purge()
|
|
element.Name = "/".join(obj.name.split("/")[1:])
|
|
AttributeData.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
|
|
|
|
|
def active_object_callback():
|
|
obj = bpy.context.active_object
|
|
for obj in bpy.context.selected_objects:
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
continue
|
|
stored_obj = IfcStore.get_element(obj.BIMObjectProperties.ifc_definition_id)
|
|
if stored_obj and stored_obj != obj:
|
|
bpy.ops.bim.copy_class(obj=obj.name)
|
|
|
|
|
|
def subscribe_to(object, data_path, callback):
|
|
subscribe_to = object.path_resolve(data_path, False)
|
|
bpy.msgbus.subscribe_rna(
|
|
key=subscribe_to,
|
|
owner=object,
|
|
args=(
|
|
object,
|
|
data_path,
|
|
),
|
|
notify=callback,
|
|
options={
|
|
"PERSISTENT",
|
|
},
|
|
)
|
|
|
|
|
|
def purge_module_data():
|
|
from blenderbim.bim import modules
|
|
|
|
for name, value in modules.items():
|
|
try:
|
|
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
|
|
except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
getattr(value, "prop").purge()
|
|
except AttributeError:
|
|
pass
|
|
|
|
|
|
@persistent
|
|
def loadIfcStore(scene):
|
|
IfcStore.purge()
|
|
ifc_file = IfcStore.get_file()
|
|
if not ifc_file:
|
|
return
|
|
IfcStore.get_schema()
|
|
[
|
|
IfcStore.link_element(ifc_file.by_id(o.BIMObjectProperties.ifc_definition_id), o)
|
|
for o in bpy.data.objects
|
|
if o.BIMObjectProperties.ifc_definition_id
|
|
]
|
|
purge_module_data()
|
|
|
|
|
|
@persistent
|
|
def ensureIfcExported(scene):
|
|
if IfcStore.get_file() and not bpy.context.scene.BIMProperties.ifc_file:
|
|
bpy.ops.export_ifc.bim("INVOKE_DEFAULT")
|
|
|
|
|
|
def get_application(ifc):
|
|
version = get_application_version()
|
|
for element in ifc.by_type("IfcApplication"):
|
|
if element.ApplicationIdentifier == "BlenderBIM" and element.Version == version:
|
|
return element
|
|
return ifc.create_entity(
|
|
"IfcApplication",
|
|
**{
|
|
"ApplicationDeveloper": create_application_organisation(ifc),
|
|
"Version": get_application_version(),
|
|
"ApplicationFullName": "BlenderBIM Add-on",
|
|
"ApplicationIdentifier": "BlenderBIM",
|
|
},
|
|
)
|
|
|
|
|
|
def get_application_version():
|
|
return ".".join(
|
|
[
|
|
str(x)
|
|
for x in [
|
|
addon.bl_info.get("version", (-1, -1, -1))
|
|
for addon in addon_utils.modules()
|
|
if addon.bl_info["name"] == "BlenderBIM"
|
|
][0]
|
|
]
|
|
)
|
|
|
|
|
|
def create_application_organisation(ifc):
|
|
return ifc.create_entity(
|
|
"IfcOrganization",
|
|
**{
|
|
"Name": "IfcOpenShell",
|
|
"Description": "IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.",
|
|
"Roles": [ifc.create_entity("IfcActorRole", **{"Role": "USERDEFINED", "UserDefinedRole": "CONTRIBUTOR"})],
|
|
"Addresses": [
|
|
ifc.create_entity(
|
|
"IfcTelecomAddress",
|
|
**{
|
|
"Purpose": "USERDEFINED",
|
|
"UserDefinedPurpose": "WEBPAGE",
|
|
"Description": "The main webpage of the software collection.",
|
|
"WWWHomePageURL": "https://ifcopenshell.org",
|
|
},
|
|
),
|
|
ifc.create_entity(
|
|
"IfcTelecomAddress",
|
|
**{
|
|
"Purpose": "USERDEFINED",
|
|
"UserDefinedPurpose": "WEBPAGE",
|
|
"Description": "The BlenderBIM Add-on webpage of the software collection.",
|
|
"WWWHomePageURL": "https://blenderbim.org",
|
|
},
|
|
),
|
|
ifc.create_entity(
|
|
"IfcTelecomAddress",
|
|
**{
|
|
"Purpose": "USERDEFINED",
|
|
"UserDefinedPurpose": "REPOSITORY",
|
|
"Description": "The source code repository of the software collection.",
|
|
"WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git",
|
|
},
|
|
),
|
|
],
|
|
},
|
|
)
|
|
|
|
|
|
@persistent
|
|
def setDefaultProperties(scene):
|
|
global global_subscription_owner
|
|
active_object_key = bpy.types.LayerObjects, "active"
|
|
bpy.msgbus.subscribe_rna(
|
|
key=active_object_key, owner=global_subscription_owner, args=(), notify=active_object_callback
|
|
)
|
|
ifcopenshell.api.owner.settings.get_person = (
|
|
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person))
|
|
if bpy.context.scene.BIMOwnerProperties.user_person
|
|
else None
|
|
)
|
|
ifcopenshell.api.owner.settings.get_organisation = (
|
|
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation))
|
|
if bpy.context.scene.BIMOwnerProperties.user_organisation
|
|
else None
|
|
)
|
|
ifcopenshell.api.owner.settings.get_application = get_application
|
|
if len(bpy.context.scene.DocProperties.drawing_styles) == 0:
|
|
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
|
drawing_style.name = "Technical"
|
|
drawing_style.render_type = "VIEWPORT"
|
|
drawing_style.raster_style = json.dumps(
|
|
{
|
|
"bpy.data.worlds[0].color": (1, 1, 1),
|
|
"bpy.context.scene.render.engine": "BLENDER_WORKBENCH",
|
|
"bpy.context.scene.render.film_transparent": False,
|
|
"bpy.context.scene.display.shading.show_object_outline": True,
|
|
"bpy.context.scene.display.shading.show_cavity": False,
|
|
"bpy.context.scene.display.shading.cavity_type": "BOTH",
|
|
"bpy.context.scene.display.shading.curvature_ridge_factor": 1,
|
|
"bpy.context.scene.display.shading.curvature_valley_factor": 1,
|
|
"bpy.context.scene.view_settings.view_transform": "Standard",
|
|
"bpy.context.scene.display.shading.light": "FLAT",
|
|
"bpy.context.scene.display.shading.color_type": "SINGLE",
|
|
"bpy.context.scene.display.shading.single_color": (1, 1, 1),
|
|
"bpy.context.scene.display.shading.show_shadows": False,
|
|
"bpy.context.scene.display.shading.shadow_intensity": 0.5,
|
|
"bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5),
|
|
"bpy.context.scene.view_settings.use_curve_mapping": False,
|
|
"space.overlay.show_wireframes": True,
|
|
"space.overlay.wireframe_threshold": 0,
|
|
"space.overlay.show_floor": False,
|
|
"space.overlay.show_axis_x": False,
|
|
"space.overlay.show_axis_y": False,
|
|
"space.overlay.show_axis_z": False,
|
|
"space.overlay.show_object_origins": False,
|
|
"space.overlay.show_relationship_lines": False,
|
|
}
|
|
)
|
|
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
|
drawing_style.name = "Shaded"
|
|
drawing_style.render_type = "VIEWPORT"
|
|
drawing_style.raster_style = json.dumps(
|
|
{
|
|
"bpy.data.worlds[0].color": (1, 1, 1),
|
|
"bpy.context.scene.render.engine": "BLENDER_WORKBENCH",
|
|
"bpy.context.scene.render.film_transparent": False,
|
|
"bpy.context.scene.display.shading.show_object_outline": True,
|
|
"bpy.context.scene.display.shading.show_cavity": True,
|
|
"bpy.context.scene.display.shading.cavity_type": "BOTH",
|
|
"bpy.context.scene.display.shading.curvature_ridge_factor": 1,
|
|
"bpy.context.scene.display.shading.curvature_valley_factor": 1,
|
|
"bpy.context.scene.view_settings.view_transform": "Standard",
|
|
"bpy.context.scene.display.shading.light": "STUDIO",
|
|
"bpy.context.scene.display.shading.color_type": "MATERIAL",
|
|
"bpy.context.scene.display.shading.single_color": (1, 1, 1),
|
|
"bpy.context.scene.display.shading.show_shadows": True,
|
|
"bpy.context.scene.display.shading.shadow_intensity": 0.5,
|
|
"bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5),
|
|
"bpy.context.scene.view_settings.use_curve_mapping": False,
|
|
"space.overlay.show_wireframes": True,
|
|
"space.overlay.wireframe_threshold": 0,
|
|
"space.overlay.show_floor": False,
|
|
"space.overlay.show_axis_x": False,
|
|
"space.overlay.show_axis_y": False,
|
|
"space.overlay.show_axis_z": False,
|
|
"space.overlay.show_object_origins": False,
|
|
"space.overlay.show_relationship_lines": False,
|
|
}
|
|
)
|
|
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
|
drawing_style.name = "Blender Default"
|
|
drawing_style.render_type = "DEFAULT"
|
|
bpy.ops.bim.save_drawing_style(index="2")
|