2021-08-17 08:39:38 +10:00
|
|
|
# IfcSverchok - IFC Sverchok extension
|
2022-11-09 01:49:01 +01:00
|
|
|
# Copyright (C) 2022 Martina Jakubowska <martina@jakubowska.dk>
|
2021-08-17 08:39:38 +10:00
|
|
|
#
|
|
|
|
|
# This file is part of IfcSverchok.
|
|
|
|
|
#
|
|
|
|
|
# IfcSverchok is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# IfcSverchok is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with IfcSverchok. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
bl_info = {
|
|
|
|
|
"name": "IFC for Sverchok",
|
|
|
|
|
"author": "Dion Moult",
|
2020-10-25 18:17:10 +11:00
|
|
|
"version": (0, 0, 999999),
|
2020-09-22 21:22:10 +10:00
|
|
|
"blender": (2, 90, 0),
|
|
|
|
|
"location": "Node Editor",
|
|
|
|
|
"category": "Node",
|
2020-10-13 20:30:00 +11:00
|
|
|
"description": "An extension to Sverchok to work with IFC data",
|
2020-10-25 18:17:10 +11:00
|
|
|
"tracker_url": "https://github.com/IfcOpenShell/IfcOpenShell/issues",
|
2020-09-22 21:22:10 +10:00
|
|
|
"warning": "",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
import importlib
|
|
|
|
|
import nodeitems_utils
|
2022-11-09 01:49:01 +01:00
|
|
|
from sverchok.core import make_node_list
|
2020-09-22 21:22:10 +10:00
|
|
|
from sverchok.utils import auto_gather_node_classes, get_node_class_reference
|
2022-11-09 01:49:01 +01:00
|
|
|
from sverchok.menu import SverchNodeItem, SverchNodeCategory
|
2022-09-08 01:18:20 +02:00
|
|
|
from sverchok.utils.extra_categories import (
|
|
|
|
|
register_extra_category_provider,
|
|
|
|
|
unregister_extra_category_provider,
|
|
|
|
|
)
|
2020-09-22 21:22:10 +10:00
|
|
|
from sverchok.ui.nodeview_space_menu import make_extra_category_menus
|
|
|
|
|
from sverchok.utils.logging import info, debug
|
2022-11-09 01:49:01 +01:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
|
|
|
|
|
def nodes_index():
|
|
|
|
|
return [
|
2020-11-01 19:24:01 +07:00
|
|
|
(
|
2020-09-22 21:22:10 +10:00
|
|
|
"IFC",
|
|
|
|
|
[
|
2020-10-01 14:47:42 +10:00
|
|
|
("ifc.create_file", "SvIfcCreateFile"),
|
|
|
|
|
("ifc.read_file", "SvIfcReadFile"),
|
|
|
|
|
("ifc.write_file", "SvIfcWriteFile"),
|
|
|
|
|
("ifc.create_entity", "SvIfcCreateEntity"),
|
2020-10-10 10:21:17 +11:00
|
|
|
("ifc.create_shape", "SvIfcCreateShape"),
|
2020-10-13 20:13:59 +11:00
|
|
|
("ifc.read_entity", "SvIfcReadEntity"),
|
2022-10-31 18:50:17 +01:00
|
|
|
("ifc.pick_ifc_class", "SvIfcPickIfcClass"),
|
2020-10-08 20:22:18 +11:00
|
|
|
("ifc.by_id", "SvIfcById"),
|
|
|
|
|
("ifc.by_guid", "SvIfcByGuid"),
|
|
|
|
|
("ifc.by_type", "SvIfcByType"),
|
2020-10-09 21:05:00 +11:00
|
|
|
("ifc.by_query", "SvIfcByQuery"),
|
2020-10-11 12:32:23 +11:00
|
|
|
("ifc.add", "SvIfcAdd"),
|
2022-09-09 09:01:01 +02:00
|
|
|
("ifc.add_pset", "SvIfcAddPset"),
|
|
|
|
|
("ifc.add_spatial_element", "SvIfcAddSpatialElement"),
|
2020-10-11 13:13:33 +11:00
|
|
|
("ifc.remove", "SvIfcRemove"),
|
2020-10-13 19:40:42 +11:00
|
|
|
("ifc.generate_guid", "SvIfcGenerateGuid"),
|
2020-10-13 20:25:35 +11:00
|
|
|
("ifc.get_property", "SvIfcGetProperty"),
|
2020-10-13 20:30:00 +11:00
|
|
|
("ifc.get_attribute", "SvIfcGetAttribute"),
|
2020-10-09 21:17:18 +11:00
|
|
|
("ifc.select_blender_objects", "SvIfcSelectBlenderObjects"),
|
2021-07-18 12:58:27 +10:00
|
|
|
("ifc.api", "SvIfcApi"),
|
2022-09-08 01:18:20 +02:00
|
|
|
("ifc.api_WIP", "SvIfcApiWIP"),
|
2022-10-23 16:18:42 +02:00
|
|
|
("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcRepr"),
|
|
|
|
|
("ifc.sverchok_to_ifc", "SvIfcSverchokToIfcRepr"),
|
2022-08-25 22:18:53 +02:00
|
|
|
("ifc.create_project", "SvIfcCreateProject"),
|
2022-11-09 01:49:01 +01:00
|
|
|
("ifc.quick_project_setup", "SvIfcQuickProjectSetup"),
|
2020-11-01 19:24:01 +07:00
|
|
|
],
|
|
|
|
|
)
|
2020-09-22 21:22:10 +10:00
|
|
|
]
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
|
|
|
|
|
def make_node_list():
|
|
|
|
|
modules = []
|
|
|
|
|
base_name = "ifcsverchok.nodes"
|
|
|
|
|
index = nodes_index()
|
|
|
|
|
for category, items in index:
|
|
|
|
|
for module_name, node_name in items:
|
|
|
|
|
module = importlib.import_module(f".{module_name}", base_name)
|
|
|
|
|
modules.append(module)
|
|
|
|
|
return modules
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
imported_modules = make_node_list()
|
|
|
|
|
|
|
|
|
|
reload_event = False
|
|
|
|
|
|
|
|
|
|
import bpy
|
2022-11-09 01:49:01 +01:00
|
|
|
from os.path import splitext
|
2022-10-31 00:25:45 +01:00
|
|
|
import ifcopenshell
|
|
|
|
|
from ifcsverchok.ifcstore import SvIfcStore
|
2022-11-09 01:49:01 +01:00
|
|
|
|
2022-10-31 00:25:45 +01:00
|
|
|
|
2022-11-07 15:45:28 +01:00
|
|
|
class IFC_Sv_UpdateCurrent(bpy.types.Operator):
|
|
|
|
|
"""Update current Sverchok node tree"""
|
2022-11-09 01:49:01 +01:00
|
|
|
|
2022-11-07 15:45:28 +01:00
|
|
|
bl_idname = "ifc.sverchok_update_current"
|
|
|
|
|
bl_label = "Update current node tree"
|
2022-11-09 01:49:01 +01:00
|
|
|
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
2022-11-07 15:45:28 +01:00
|
|
|
|
|
|
|
|
node_group: bpy.props.StringProperty(default="")
|
|
|
|
|
force_mode: bpy.props.BoolProperty(default=False)
|
|
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = SvIfcStore.purge()
|
|
|
|
|
node_tree = context.space_data.node_tree
|
|
|
|
|
if node_tree:
|
|
|
|
|
if self.force_mode or node_tree.sv_process:
|
|
|
|
|
try:
|
|
|
|
|
bpy.context.window.cursor_set("WAIT")
|
|
|
|
|
node_tree.force_update()
|
|
|
|
|
finally:
|
|
|
|
|
bpy.context.window.cursor_set("DEFAULT")
|
2022-11-07 17:40:18 +01:00
|
|
|
self.report({"INFO"}, "Node tree updated.")
|
2022-11-09 01:49:01 +01:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
2022-11-07 15:45:28 +01:00
|
|
|
|
2022-10-31 00:25:45 +01:00
|
|
|
class IFC_Sv_write_file(bpy.types.Operator):
|
|
|
|
|
bl_idname = "ifc.write_file_panel"
|
|
|
|
|
bl_label = "Write File"
|
|
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
|
bl_description = "File path to write to."
|
|
|
|
|
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
2022-11-07 15:45:28 +01:00
|
|
|
node_group: bpy.props.StringProperty(default="")
|
|
|
|
|
force_mode: bpy.props.BoolProperty(default=False)
|
2022-10-31 00:25:45 +01:00
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def poll(cls, context):
|
|
|
|
|
return any("IFC" in n for n in context.space_data.edit_tree.nodes.keys())
|
|
|
|
|
|
2022-11-07 15:45:28 +01:00
|
|
|
def ensure_hirarchy(self, file):
|
2022-11-09 01:49:01 +01:00
|
|
|
elements_in_buildings = set()
|
|
|
|
|
if len(file.by_type("IfcBuilding")) == 0:
|
2022-11-07 15:45:28 +01:00
|
|
|
my_building = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcBuilding", name="My Building")
|
|
|
|
|
elements = ifcopenshell.util.element.get_decomposition(my_building)
|
|
|
|
|
else:
|
|
|
|
|
for building in file.by_type("IfcBuilding"):
|
|
|
|
|
elements = ifcopenshell.util.element.get_decomposition(building)
|
2022-11-09 01:49:01 +01:00
|
|
|
elements_in_buildings.update(elements)
|
2022-11-07 15:45:28 +01:00
|
|
|
|
2022-11-09 01:49:01 +01:00
|
|
|
for spatial in file.by_type("IfcSpatialElement") or file.by_type("IfcSpatialStructureElement"):
|
|
|
|
|
if not (spatial.is_a("IfcSite") or spatial.is_a("IfcBuilding")) and (spatial not in elements_in_buildings):
|
2022-11-07 15:45:28 +01:00
|
|
|
elements = ifcopenshell.util.element.get_decomposition(spatial)
|
2022-11-09 01:49:01 +01:00
|
|
|
ifcopenshell.api.run(
|
|
|
|
|
"aggregate.assign_object", file, product=spatial, relating_object=file.by_type("IfcBuilding")[0]
|
|
|
|
|
)
|
2022-11-07 15:45:28 +01:00
|
|
|
|
|
|
|
|
for building in file.by_type("IfcBuilding"):
|
|
|
|
|
elements = ifcopenshell.util.element.get_decomposition(building)
|
2022-11-09 01:49:01 +01:00
|
|
|
elements_in_buildings.update(elements)
|
2022-11-07 15:45:28 +01:00
|
|
|
|
|
|
|
|
elements = file.by_type("IfcElement")
|
|
|
|
|
for element in elements:
|
|
|
|
|
if element not in elements_in_buildings:
|
2022-11-09 01:49:01 +01:00
|
|
|
ifcopenshell.api.run(
|
|
|
|
|
"spatial.assign_container", file, product=element, relating_structure=file.by_type("IfcBuilding")[0]
|
|
|
|
|
)
|
2022-11-07 15:45:28 +01:00
|
|
|
|
|
|
|
|
for building in file.by_type("IfcBuilding"):
|
|
|
|
|
elements = ifcopenshell.util.element.get_decomposition(building)
|
|
|
|
|
if not building.Decomposes:
|
2022-11-09 01:49:01 +01:00
|
|
|
if len(file.by_type("IfcSite")) == 0:
|
2022-11-07 15:45:28 +01:00
|
|
|
ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site")
|
2022-11-09 01:49:01 +01:00
|
|
|
ifcopenshell.api.run(
|
|
|
|
|
"aggregate.assign_object", file, product=building, relating_object=file.by_type("IfcSite")[0]
|
|
|
|
|
)
|
2022-11-07 15:45:28 +01:00
|
|
|
try:
|
|
|
|
|
if file.by_type("IfcSite")[0].Decomposes[0].RelatingObject.is_a("IfcProject"):
|
|
|
|
|
continue
|
|
|
|
|
except IndexError:
|
|
|
|
|
pass
|
2022-11-09 01:49:01 +01:00
|
|
|
ifcopenshell.api.run(
|
|
|
|
|
"aggregate.assign_object",
|
|
|
|
|
file,
|
|
|
|
|
product=file.by_type("IfcSite")[0],
|
|
|
|
|
relating_object=file.by_type("IfcProject")[0],
|
|
|
|
|
)
|
2022-11-07 15:45:28 +01:00
|
|
|
self.file = file
|
|
|
|
|
return
|
|
|
|
|
|
2022-10-31 00:25:45 +01:00
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = SvIfcStore.file
|
|
|
|
|
if not self.file:
|
|
|
|
|
raise Exception("No IFC file in SvIfcStore.")
|
|
|
|
|
_, ext = splitext(self.filepath)
|
|
|
|
|
if not ext:
|
|
|
|
|
raise Exception("Bad path. Provide a path to a file.")
|
|
|
|
|
else:
|
2022-11-07 15:45:28 +01:00
|
|
|
self.ensure_hirarchy(self.file)
|
2022-10-31 00:25:45 +01:00
|
|
|
self.file.write(self.filepath)
|
2022-11-07 15:45:28 +01:00
|
|
|
self.report({"INFO"}, f"File written to: {self.filepath}")
|
2022-10-31 00:25:45 +01:00
|
|
|
return {"FINISHED"}
|
2022-11-07 15:45:28 +01:00
|
|
|
|
2022-10-31 00:25:45 +01:00
|
|
|
def invoke(self, context, event):
|
|
|
|
|
context.window_manager.fileselect_add(self)
|
|
|
|
|
return {"RUNNING_MODAL"}
|
|
|
|
|
|
2022-11-09 01:49:01 +01:00
|
|
|
|
2022-10-31 00:25:45 +01:00
|
|
|
class IFC_PT_write_file_panel(bpy.types.Panel):
|
|
|
|
|
bl_idname = "IFC_PT_write_file_panel"
|
|
|
|
|
bl_label = "Write IFC to file"
|
|
|
|
|
bl_options = {"DEFAULT_CLOSED"}
|
|
|
|
|
bl_space_type = "NODE_EDITOR"
|
|
|
|
|
bl_region_type = "UI"
|
|
|
|
|
bl_category = "IfcSverchok"
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def poll(cls, context):
|
|
|
|
|
if context.space_data.edit_tree and any("IFC" in n for n in context.space_data.edit_tree.nodes.keys()):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
2022-11-07 15:45:28 +01:00
|
|
|
ng = context.space_data.node_tree
|
2022-10-31 00:25:45 +01:00
|
|
|
layout = self.layout
|
|
|
|
|
row = layout.split(factor=0.2, align=True)
|
|
|
|
|
row = layout.row()
|
2022-11-07 17:40:18 +01:00
|
|
|
row2 = layout.row()
|
2022-11-09 01:49:01 +01:00
|
|
|
row.operator("ifc.sverchok_update_current", text="IFC Re-run all nodes")
|
2022-11-07 17:40:18 +01:00
|
|
|
row2.operator("ifc.write_file_panel")
|
2022-10-31 00:25:45 +01:00
|
|
|
|
2022-11-09 01:49:01 +01:00
|
|
|
|
|
|
|
|
CLASSES = [IFC_Sv_UpdateCurrent, IFC_Sv_write_file, IFC_PT_write_file_panel]
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
def register_nodes():
|
|
|
|
|
node_modules = make_node_list()
|
|
|
|
|
for module in node_modules:
|
|
|
|
|
module.register()
|
|
|
|
|
info("Registered %s nodes", len(node_modules))
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
def unregister_nodes():
|
|
|
|
|
global imported_modules
|
|
|
|
|
for module in reversed(imported_modules):
|
|
|
|
|
module.unregister()
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
def make_menu():
|
|
|
|
|
menu = []
|
|
|
|
|
index = nodes_index()
|
|
|
|
|
for category, items in index:
|
|
|
|
|
identifier = "IFCSVERCHOK_" + category.replace(" ", "_")
|
|
|
|
|
node_items = []
|
|
|
|
|
for item in items:
|
|
|
|
|
nodetype = item[1]
|
|
|
|
|
rna = get_node_class_reference(nodetype)
|
|
|
|
|
if not rna:
|
2022-09-08 01:18:20 +02:00
|
|
|
info(
|
|
|
|
|
"Node `%s' is not available (probably due to missing dependencies).",
|
|
|
|
|
nodetype,
|
|
|
|
|
)
|
2020-09-22 21:22:10 +10:00
|
|
|
else:
|
|
|
|
|
node_item = SverchNodeItem.new(nodetype)
|
|
|
|
|
node_items.append(node_item)
|
|
|
|
|
if node_items:
|
|
|
|
|
cat = SverchNodeCategory(identifier, category, items=node_items)
|
|
|
|
|
menu.append(cat)
|
|
|
|
|
return menu
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
class SvExCategoryProvider(object):
|
|
|
|
|
def __init__(self, identifier, menu):
|
|
|
|
|
self.identifier = identifier
|
|
|
|
|
self.menu = menu
|
|
|
|
|
|
|
|
|
|
def get_categories(self):
|
|
|
|
|
return self.menu
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
our_menu_classes = []
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
def register():
|
|
|
|
|
global our_menu_classes
|
|
|
|
|
|
|
|
|
|
debug("Registering ifcsverchok")
|
2022-10-31 00:25:45 +01:00
|
|
|
for klass in CLASSES:
|
|
|
|
|
bpy.utils.register_class(klass)
|
2020-09-22 21:22:10 +10:00
|
|
|
register_nodes()
|
|
|
|
|
extra_nodes = importlib.import_module(".nodes", "ifcsverchok")
|
|
|
|
|
auto_gather_node_classes(extra_nodes)
|
|
|
|
|
menu = make_menu()
|
|
|
|
|
menu_category_provider = SvExCategoryProvider("IFCSVERCHOK", menu)
|
2022-11-09 01:49:01 +01:00
|
|
|
register_extra_category_provider(menu_category_provider) # if 'IFCSVERCHOK' in nodeitems_utils._node_categories:
|
2020-09-22 21:22:10 +10:00
|
|
|
nodeitems_utils.register_node_categories("IFCSVERCHOK", menu)
|
|
|
|
|
our_menu_classes = make_extra_category_menus()
|
|
|
|
|
|
2020-11-01 19:24:01 +07:00
|
|
|
|
2020-09-22 21:22:10 +10:00
|
|
|
def unregister():
|
|
|
|
|
global our_menu_classes
|
|
|
|
|
if "IFCSVERCHOK" in nodeitems_utils._node_categories:
|
|
|
|
|
nodeitems_utils.unregister_node_categories("IFCSVERCHOK")
|
|
|
|
|
for clazz in our_menu_classes:
|
|
|
|
|
try:
|
|
|
|
|
bpy.utils.unregister_class(clazz)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print("Can't unregister menu class %s" % clazz)
|
|
|
|
|
print(e)
|
|
|
|
|
unregister_extra_category_provider("IFCSVERCHOK")
|
2022-09-08 01:18:20 +02:00
|
|
|
unregister_nodes()
|
2022-10-31 00:25:45 +01:00
|
|
|
for klass in CLASSES:
|
|
|
|
|
bpy.utils.unregister_class(klass)
|