From acee90fa895126e92e0fdaf5aad05d70475a1818 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Thu, 25 Aug 2022 22:01:35 +0200 Subject: [PATCH 01/21] Added new nodes: api_WIP, bmesh_to_ifc, create_project and quick_project_setup Modified nodes: api, create_entity --- src/ifcsverchok/nodes/ifc/api.py | 31 +++-- src/ifcsverchok/nodes/ifc/api_WIP.py | 118 ++++++++++++++++++ src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 104 +++++++++++++++ src/ifcsverchok/nodes/ifc/by_type.py | 2 +- src/ifcsverchok/nodes/ifc/create_entity.py | 12 +- src/ifcsverchok/nodes/ifc/create_file.py | 1 - src/ifcsverchok/nodes/ifc/create_project.py | 80 ++++++++++++ src/ifcsverchok/nodes/ifc/create_shape.py | 16 +++ .../nodes/ifc/quick_project_setup.py | 96 ++++++++++++++ 9 files changed, 445 insertions(+), 15 deletions(-) create mode 100644 src/ifcsverchok/nodes/ifc/api_WIP.py create mode 100644 src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py create mode 100644 src/ifcsverchok/nodes/ifc/create_project.py create mode 100644 src/ifcsverchok/nodes/ifc/quick_project_setup.py diff --git a/src/ifcsverchok/nodes/ifc/api.py b/src/ifcsverchok/nodes/ifc/api.py index f81e1a9948..236b0cd1e2 100644 --- a/src/ifcsverchok/nodes/ifc/api.py +++ b/src/ifcsverchok/nodes/ifc/api.py @@ -26,10 +26,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode -def update_usecase(self, context): - module_usecase = self.get_module_usecase() - if module_usecase: - self.generate_node(*module_usecase) + class SvIfcTooltip(bpy.types.Operator): @@ -46,13 +43,25 @@ class SvIfcTooltip(bpy.types.Operator): class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + + def update_usecase(self, context): + try: + module_usecase = self.get_module_usecase() + if module_usecase: + self.generate_node(*module_usecase) + except: + raise Exception( + f"Couldn't run generate_node(). Module usecase: {module_usecase}" + ) + bl_idname = "SvIfcApi" bl_label = "IFC API" tooltip: StringProperty(name="Tooltip") - usecase: StringProperty(name="Usecase", update=update_usecase) + usecase: StringProperty(update=updateNode) def sv_init(self, context): - self.inputs.new("SvStringsSocket", "usecase").prop_name = "usecase" + input_socket = self.inputs.new("SvStringsSocket", "usecase").use_prop = True + input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" self.outputs.new("SvVerticesSocket", "file") def draw_buttons(self, context, layout): @@ -63,8 +72,9 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor print("process") module_usecase = self.get_module_usecase() if module_usecase: + self.generate_node(*module_usecase) self.sv_input_names = [i.name for i in self.inputs] - super().process() + super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh def get_module_usecase(self): usecase = self.inputs["usecase"].sv_get()[0][0] @@ -75,7 +85,7 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor try: node_data = ifcopenshell.api.extract_docs(module, usecase) except: - print("Node not yet implemented:", module, usecase) + raise Exception("Node not yet implemented:", module, usecase) return while len(self.inputs) > 1: self.inputs.remove(self.inputs[-1]) @@ -83,7 +93,7 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor self.tooltip = "" for name, data in node_data["inputs"].items(): setattr(SvIfcApi, name, StringProperty(name=name, update=updateNode)) - self.inputs.new("SvStringsSocket", name).prop_name = name + self.inputs.new("SvStringsSocket", name).use_prop = True if "default" in data: self.tooltip = f"{name} ({data['default']}): {data['description']}\n" else: @@ -97,6 +107,7 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, **settings)]) + def register(): bpy.utils.register_class(SvIfcTooltip) bpy.utils.register_class(SvIfcApi) @@ -104,4 +115,4 @@ def register(): def unregister(): bpy.utils.unregister_class(SvIfcApi) - bpy.utils.unregister_class(SvIfcTooltip) + bpy.utils.unregister_class(SvIfcTooltip) \ No newline at end of file diff --git a/src/ifcsverchok/nodes/ifc/api_WIP.py b/src/ifcsverchok/nodes/ifc/api_WIP.py new file mode 100644 index 0000000000..963dc29db5 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/api_WIP.py @@ -0,0 +1,118 @@ + +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcopenshell.api +import ifcsverchok.helper +from bpy.props import StringProperty, EnumProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode +import importlib + + + + +class SvIfcTooltip(bpy.types.Operator): + bl_idname = "node.sv_ifc_tooltip" + bl_label = "IFC Info" + tooltip: bpy.props.StringProperty() + + @classmethod + def description(cls, context, properties): + return properties.tooltip + + def execute(self, context): + return {"FINISHED"} + + +class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + + def update_usecase(self, context): + # update is not getting run rn + try: + module_usecase = self.get_module_usecase() + #if module_usecase: + self.generate_node(*module_usecase) + except: + raise Exception( + f"Couldn't run generate_node(). Module usecase: {module_usecase}" + ) + + bl_idname = "SvIfcApiWIP" + bl_label = "IFC API WIP" + tooltip: StringProperty(name="Tooltip") + usecase: StringProperty(update=updateNode) + + def sv_init(self, context): + input_socket = self.inputs.new("SvStringsSocket", "usecase").use_prop = True + # input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" + self.outputs.new("SvVerticesSocket", "file") + + def draw_buttons(self, context, layout): + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False) + op.tooltip = self.tooltip + + def process(self): + print("process") + module_usecase = self.get_module_usecase() + if module_usecase: + self.generate_node(*module_usecase) # does this actually add to self.inputs? + self.sv_input_names = [i.name for i in self.inputs] + #super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh + self.process() + + def get_module_usecase(self): + usecase = self.inputs["usecase"].sv_get()[0][0] + if usecase: + return usecase.split(".") + + def generate_node(self, module, usecase): + importlib.import_module(f"ifcopenshell.api.{module}.{usecase}") + init_func = getattr(getattr(ifcopenshell.api, module), usecase).Usecase.__init__ + if "settings" in init_func.__code__.co_varnames: + args = list(init_func.__code__.co_consts[3]) + args.insert(0, 'file') + else: + args = ['file'] + + while len(self.inputs) > 1: + self.inputs.remove(self.inputs[-1]) + + for name in args: + print("name type", type(name)) + setattr(SvIfcApiWIP, str(name), StringProperty(name=str(name), update=updateNode)) + self.inputs.new("SvStringsSocket", str(name)).use_prop = True + + def process_ifc(self, usecase, *setting_values): + if usecase: + settings = dict(zip(self.sv_input_names[1:], setting_values)) + settings = {k: v for k, v in settings.items() if v != ""} + self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, **settings)]) + + + +def register(): + bpy.utils.register_class(SvIfcTooltip) + bpy.utils.register_class(SvIfcApiWIP) + + +def unregister(): + bpy.utils.unregister_class(SvIfcApiWIP) + bpy.utils.unregister_class(SvIfcTooltip) \ No newline at end of file diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py new file mode 100644 index 0000000000..6894cd8554 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -0,0 +1,104 @@ +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcsverchok.helper +import ifcopenshell.api +import blenderbim.tool as tool +import blenderbim.core.geometry as core +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode +from blenderbim.bim.module.root.prop import get_contexts + + +class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + """ + Triggers: BMesh to Ifc Geo + Tooltip: Blender mesh to Ifc Geometric Representation + """ + bl_idname = "SvIfcBMeshToIfcGeo" + bl_label = "IFC Blender Mesh to IFC Geo" + tooltip: StringProperty(name="Tooltip") + context_id: bpy.props.IntProperty() + + def sv_init(self, context): + input_socket = self.inputs.new("SvStringsSocket", "file") + input_socket.tooltip = "ifc file to add the geometry to" + input_socket = self.inputs.new("SvObjectSocket", "blender_object") + input_socket.tooltip = "Pick or pass Blender Mesh object" + input_socket = self.inputs.new("SvStringsSocket", "ifc_representation_class") + input_socket.tooltip = "Whether to cast a mesh into a particular class" + self.outputs.new("SvVerticesSocket", "file") + self.outputs.new("SvVerticesSocket", "representation") + + def draw_buttons(self, context, layout): + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Description?" + #op.tooltip = self.tooltip + + def process(self): + print("Running process...") + + # file + file = self.inputs["file"].sv_get()[0][0] + + # blender mesh + blender_object = self.inputs["blender_object"].sv_get()[0] + print("blender object: ", blender_object) + + #geometry + geometry = blender_object.data + print("geometry: ", geometry) + + #run process_ifc + self.process_ifc(file, blender_object, geometry) + + def process_ifc(self, file, blender_object, geometry): + #get context + try: + for context in file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): + if context.get_info()["ContextType"] == "Model" and context.get_info()["ContextIdentifier"] == "Body": + repr_context= context + print("pop", context) + elif context.get_info()["ContextType"] == "Model": + repr_context= context + except: + raise Exception( + "Ifc Geometric Representation Context is missing." + ) + + representation = [ifcopenshell.api.run("geometry.add_representation", file, should_run_listeners=False,blender_object = blender_object, geometry=geometry, context = repr_context)] + print("representation: ", representation) + try: + self.outputs["file"].sv_set([[file]]) + self.outputs["representation"].sv_set([representation]) + except: + raise Exception( + "Couldn't write to file. Representation: {}".format( + representation + ) + ) + + +def register(): + bpy.utils.register_class(SvIfcBMeshToIfcGeo) + + +def unregister(): + bpy.utils.unregister_class(SvIfcBMeshToIfcGeo) diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index ae91242e1a..c27be8426c 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -115,4 +115,4 @@ def register(): def unregister(): - bpy.utils.unregister_class(SvIfcByType) + bpy.utils.unregister_class(SvIfcByType) \ No newline at end of file diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 43bd9160f0..8fa03d9136 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -54,16 +54,17 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.generate_inputs(ifc_class) try: for i in range(0, len(self.inputs)): - self.inputs[i].sv_get() + input = self.inputs[i].sv_get() except: # This occurs when a blender save file is reloaded self.generate_inputs(ifc_class) for i in range(0, self.entity_schema.attribute_count()): self.sv_input_names.append(self.entity_schema.attribute_by_index(i).name()) - super().process() - + self.process() + def generate_inputs(self, ifc_class): + # print("generate_inputs...") while len(self.inputs) > 2: self.inputs.remove(self.inputs[-1]) for i in range(0, self.entity_schema.attribute_count()): @@ -77,12 +78,16 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper for i in range(0, len(entity)): try: value = attributes[i] + # print("value (attribute[i]): ", value, "|value type: ", type(value)) if isinstance(value, str) and value == "": value = None except: value = None if value is None and entity.is_a("IfcRoot") and i == 0: value = ifcopenshell.guid.new() + if value is not None and entity.attribute_name(i) == "Representation": + value = file.createIfcProductDefinitionShape(None, None, Representations = [value]) + #product_shape = ifcopenshell.api.run("geometry.assign_representation", file, product = , representation = value) if value is not None: value = self.cast_value(self.entity_schema.attribute_by_index(i), value) try: @@ -93,6 +98,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper ifc_class, entity.attribute_name(i), value ) ) + self.outputs["file"].sv_set([[file]]) self.outputs["entity"].sv_set([[entity]]) diff --git a/src/ifcsverchok/nodes/ifc/create_file.py b/src/ifcsverchok/nodes/ifc/create_file.py index 1e8b1869ff..4005190af7 100644 --- a/src/ifcsverchok/nodes/ifc/create_file.py +++ b/src/ifcsverchok/nodes/ifc/create_file.py @@ -1,4 +1,3 @@ - # IfcSverchok - IFC Sverchok extension # Copyright (C) 2020, 2021 Dion Moult # diff --git a/src/ifcsverchok/nodes/ifc/create_project.py b/src/ifcsverchok/nodes/ifc/create_project.py new file mode 100644 index 0000000000..d96f6c545f --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/create_project.py @@ -0,0 +1,80 @@ +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcsverchok.helper +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode +# from ifcopenshell import template + +class SvIfcCreateProject(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcCreateProject" + bl_label = "IFC Create Project" + + def sv_init(self, context): + input_socket = self.inputs.new("SvStringsSocket", "file") + input_socket.tooltip = "ifc file to add the project to" + input_socket = self.inputs.new("SvStringsSocket", "project_name") + input_socket.tooltip = "Project name" + self.outputs.new("SvVerticesSocket", "file") + + def draw_buttons(self, context, layout): + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Adds project, unit and context to IFC file" + #op.tooltip = self.tooltip + + def process(self): + #file + file = self.inputs["file"].sv_get()[0][0] + if file: + schema_name = file.wrapped_data.schema + else: + schema_name = "IFC4" + + #project name + project_name = self.inputs["project_name"].sv_get()[0][0] + print("project name:", project_name) + self.process_ifc(file, project_name) + + + def process_ifc(self, file, project_name): + + # create project + project = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcProject", name=str(project_name)) + lengthunit = ifcopenshell.api.run("unit.add_si_unit", file, unit_type="LENGTHUNIT", name="METRE") + ifcopenshell.api.run("unit.assign_unit", file, units=[lengthunit]) + model = ifcopenshell.api.run("context.add_context", file, context_type="Model") + context = ifcopenshell.api.run( + "context.add_context", + file, + context_type="Model", + context_identifier="Body", + target_view="MODEL_VIEW", + parent=model, + ) + + self.outputs["file"].sv_set([[file]]) + + +def register(): + bpy.utils.register_class(SvIfcCreateProject) + + +def unregister(): + bpy.utils.unregister_class(SvIfcCreateProject) diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index 1f5cad07b1..430ed4f711 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -26,6 +26,8 @@ from bpy.props import StringProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode +from sverchok.data_structure import zip_long_repeat + class SvIfcCreateShapeRefresh(bpy.types.Operator): bl_idname = "node.sv_ifc_create_shape_refresh" @@ -57,8 +59,22 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. def process(self): self.sv_input_names = ["file", "entity"] super().process() + + def process_helper(self): + print("Hello from helper") + sv_inputs_nested = [] + for name in self.sv_input_names: + sv_inputs_nested.append(self.inputs[name].sv_get()) + print(24*"#","\n", "sv_input: ", self.inputs[name].sv_get(), "input type: ", type(self.inputs[name].sv_get()), "\n", "#"*24) + for sv_input_nested in zip_long_repeat(*sv_inputs_nested): + for sv_input in zip_long_repeat(*sv_input_nested): + sv_input = list(sv_input) + print(24*"#","\n", "sv_input post zip_long_repeat: ", sv_input, "input type: ", type(sv_input), "\n", "#"*24) + self.process_ifc(*sv_input) def process_ifc(self, file, entity): + print("process ifc...") + print("entity: ", entity) try: if not entity.is_a("IfcProduct"): return diff --git a/src/ifcsverchok/nodes/ifc/quick_project_setup.py b/src/ifcsverchok/nodes/ifc/quick_project_setup.py new file mode 100644 index 0000000000..5292be4c73 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/quick_project_setup.py @@ -0,0 +1,96 @@ +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +from email.mime import application +import bpy +import ifcopenshell +import ifcsverchok.helper +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode +from ifcopenshell import template + +class SvIfcQuickProjectSetup(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcQuickProjectSetup" + bl_label = "IFC Quick Project Setup" + schema_identifier: StringProperty(name="schema_identifier", update=updateNode, default="IFC4") + timestring: StringProperty(name="timestring", update=updateNode) + application: StringProperty(name="application", update=updateNode) + application_version: StringProperty(name="application_version", update=updateNode) + timestamp: StringProperty(name="timestamp", update=updateNode) + + + def sv_init(self, context): + input_socket = self.inputs.new("SvStringsSocket", "filename") + input_socket.tooltip = "Ifc file name" + input_socket = self.inputs.new("SvStringsSocket", "timestring") + input_socket.tooltip = "Timestring, default = current time" + input_socket = self.inputs.new("SvStringsSocket", "organization") + input_socket.tooltip = "Organization" + input_socket = self.inputs.new("SvStringsSocket", "creator") + input_socket.tooltip = "creator" + input_socket = self.inputs.new("SvStringsSocket", "schema_identifier") + input_socket.tooltip = "Schema, default = 'IFC4'" + input_socket = self.inputs.new("SvStringsSocket", "application_version") + input_socket.tooltip = "Application version" + input_socket = self.inputs.new("SvStringsSocket", "timestamp") + input_socket.tooltip = "Timestamp, default = current time" + input_socket = self.inputs.new("SvStringsSocket", "application") + input_socket.tooltip = "Application, default = 'IfcOpenShell'" + input_socket = self.inputs.new("SvStringsSocket", "project_globalid") + input_socket.tooltip = "Project GlobalId" + input_socket = self.inputs.new("SvStringsSocket", "project_name") + input_socket.tooltip = "Project name" + self.outputs.new("SvVerticesSocket", "file") + + def draw_buttons(self, context, layout): + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Quick Project Setup: creates Ifc file and sets up a basic project" + #op.tooltip = self.tooltip + + def process(self): + self.sv_input_names = [i.name for i in self.inputs] + print("inputnames: ", self.sv_input_names) + super().process() + + def process_ifc(self, *setting_values): + print("setting values: ", setting_values) + settings = dict(zip(self.sv_input_names, setting_values)) + print("settings: ", settings) + settings = {k: v for k, v in settings.items() if v != ""} + file = template.create( + filename=settings['filename'], + timestring=settings['timestring'], + organization=settings['organization'], + creator=settings['creator'], + schema_identifier=settings['schema_identifier'], + application_version=settings['application_version'], + timestamp=settings['timestamp'], + application=settings['application'], + project_globalid=settings['project_globalid'], + project_name=settings['project_name'], + ) + + self.outputs["file"].sv_set([[file]]) + + +def register(): + bpy.utils.register_class(SvIfcQuickProjectSetup) + + +def unregister(): + bpy.utils.unregister_class(SvIfcQuickProjectSetup) From dd2f4586c75e1fd7ac5124b491202a0349413d69 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Thu, 25 Aug 2022 22:18:53 +0200 Subject: [PATCH 02/21] added new nodes to node index --- src/ifcsverchok/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 5749501973..1eaca6b5df 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -63,6 +63,9 @@ def nodes_index(): ("ifc.get_attribute", "SvIfcGetAttribute"), ("ifc.select_blender_objects", "SvIfcSelectBlenderObjects"), ("ifc.api", "SvIfcApi"), + ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), + ("ifc.create_project", "SvIfcCreateProject"), + ], ) ] @@ -157,4 +160,4 @@ def unregister(): print("Can't unregister menu class %s" % clazz) print(e) unregister_extra_category_provider("IFCSVERCHOK") - unregister_nodes() + unregister_nodes() \ No newline at end of file From 8b8024ba7e02bbe8a0be702dd6089ea435d4df93 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Thu, 25 Aug 2022 22:45:52 +0200 Subject: [PATCH 03/21] fixed a typo-bug --- src/ifcsverchok/nodes/ifc/api_WIP.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/api_WIP.py b/src/ifcsverchok/nodes/ifc/api_WIP.py index 963dc29db5..f7b6769057 100644 --- a/src/ifcsverchok/nodes/ifc/api_WIP.py +++ b/src/ifcsverchok/nodes/ifc/api_WIP.py @@ -48,8 +48,8 @@ class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc # update is not getting run rn try: module_usecase = self.get_module_usecase() - #if module_usecase: - self.generate_node(*module_usecase) + if module_usecase: + self.generate_node(*module_usecase) except: raise Exception( f"Couldn't run generate_node(). Module usecase: {module_usecase}" @@ -61,7 +61,7 @@ class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc usecase: StringProperty(update=updateNode) def sv_init(self, context): - input_socket = self.inputs.new("SvStringsSocket", "usecase").use_prop = True + self.inputs.new("SvStringsSocket", "usecase").use_prop = True # input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" self.outputs.new("SvVerticesSocket", "file") @@ -73,10 +73,10 @@ class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc print("process") module_usecase = self.get_module_usecase() if module_usecase: - self.generate_node(*module_usecase) # does this actually add to self.inputs? + self.generate_node(*module_usecase) self.sv_input_names = [i.name for i in self.inputs] - #super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh - self.process() + super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh + def get_module_usecase(self): usecase = self.inputs["usecase"].sv_get()[0][0] @@ -96,9 +96,9 @@ class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc self.inputs.remove(self.inputs[-1]) for name in args: - print("name type", type(name)) + # print("name type", type(name)) setattr(SvIfcApiWIP, str(name), StringProperty(name=str(name), update=updateNode)) - self.inputs.new("SvStringsSocket", str(name)).use_prop = True + self.inputs.new("SvStringsSocket", str(name)) def process_ifc(self, usecase, *setting_values): if usecase: From 7c2162f0549aadf37cdba18022a4fc97e477558d Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Sun, 4 Sep 2022 23:36:30 +0200 Subject: [PATCH 04/21] fixed api_WIP, minor cleanup in other nodes --- src/ifcsverchok/nodes/ifc/api.py | 30 ++---- src/ifcsverchok/nodes/ifc/api_WIP.py | 91 ++++++++++++------- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 15 +-- src/ifcsverchok/nodes/ifc/create_entity.py | 4 +- src/ifcsverchok/nodes/ifc/create_project.py | 1 - src/ifcsverchok/nodes/ifc/create_shape.py | 16 +--- .../nodes/ifc/quick_project_setup.py | 3 - 7 files changed, 73 insertions(+), 87 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/api.py b/src/ifcsverchok/nodes/ifc/api.py index 236b0cd1e2..7dbcc77acf 100644 --- a/src/ifcsverchok/nodes/ifc/api.py +++ b/src/ifcsverchok/nodes/ifc/api.py @@ -26,7 +26,11 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode - +def update_usecase(self, context): + print("API - running update usecase!") + module_usecase = self.get_module_usecase() + if module_usecase: + self.generate_node(*module_usecase) class SvIfcTooltip(bpy.types.Operator): @@ -43,25 +47,13 @@ class SvIfcTooltip(bpy.types.Operator): class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): - - def update_usecase(self, context): - try: - module_usecase = self.get_module_usecase() - if module_usecase: - self.generate_node(*module_usecase) - except: - raise Exception( - f"Couldn't run generate_node(). Module usecase: {module_usecase}" - ) - bl_idname = "SvIfcApi" bl_label = "IFC API" tooltip: StringProperty(name="Tooltip") - usecase: StringProperty(update=updateNode) + usecase: StringProperty(name="Usecase", update=update_usecase) def sv_init(self, context): - input_socket = self.inputs.new("SvStringsSocket", "usecase").use_prop = True - input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" + self.inputs.new("SvStringsSocket", "usecase").prop_name = "usecase" self.outputs.new("SvVerticesSocket", "file") def draw_buttons(self, context, layout): @@ -72,9 +64,8 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor print("process") module_usecase = self.get_module_usecase() if module_usecase: - self.generate_node(*module_usecase) self.sv_input_names = [i.name for i in self.inputs] - super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh + super().process() def get_module_usecase(self): usecase = self.inputs["usecase"].sv_get()[0][0] @@ -85,7 +76,7 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor try: node_data = ifcopenshell.api.extract_docs(module, usecase) except: - raise Exception("Node not yet implemented:", module, usecase) + print("Node not yet implemented:", module, usecase) return while len(self.inputs) > 1: self.inputs.remove(self.inputs[-1]) @@ -93,7 +84,7 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor self.tooltip = "" for name, data in node_data["inputs"].items(): setattr(SvIfcApi, name, StringProperty(name=name, update=updateNode)) - self.inputs.new("SvStringsSocket", name).use_prop = True + self.inputs.new("SvStringsSocket", name).prop_name = name if "default" in data: self.tooltip = f"{name} ({data['default']}): {data['description']}\n" else: @@ -107,7 +98,6 @@ class SvIfcApi(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCor self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, **settings)]) - def register(): bpy.utils.register_class(SvIfcTooltip) bpy.utils.register_class(SvIfcApi) diff --git a/src/ifcsverchok/nodes/ifc/api_WIP.py b/src/ifcsverchok/nodes/ifc/api_WIP.py index f7b6769057..c546d07a64 100644 --- a/src/ifcsverchok/nodes/ifc/api_WIP.py +++ b/src/ifcsverchok/nodes/ifc/api_WIP.py @@ -28,7 +28,6 @@ import importlib - class SvIfcTooltip(bpy.types.Operator): bl_idname = "node.sv_ifc_tooltip" bl_label = "IFC Info" @@ -44,37 +43,48 @@ class SvIfcTooltip(bpy.types.Operator): class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): - def update_usecase(self, context): - # update is not getting run rn - try: - module_usecase = self.get_module_usecase() - if module_usecase: - self.generate_node(*module_usecase) - except: - raise Exception( - f"Couldn't run generate_node(). Module usecase: {module_usecase}" - ) + # def update_usecase(self, context): + # # update_usecase is not getting run rn +# module_usecase = self.get_module_usecase() +# if module_usecase: +# self.generate_node(*module_usecase) bl_idname = "SvIfcApiWIP" bl_label = "IFC API WIP" tooltip: StringProperty(name="Tooltip") - usecase: StringProperty(update=updateNode) + usecase: StringProperty(name="usecase", update=updateNode) + current_usecase: StringProperty(name="current_usecase") def sv_init(self, context): - self.inputs.new("SvStringsSocket", "usecase").use_prop = True - # input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" + self.inputs.new("SvStringsSocket", "usecase").prop_name = "usecase" + #input_socket.tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file'" self.outputs.new("SvVerticesSocket", "file") def draw_buttons(self, context, layout): - op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False) - op.tooltip = self.tooltip + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "ifcopenshell.api usecase, written like 'module.usecase' \n E.g.: 'project.create_file" + # op.tooltip = self.tooltip def process(self): - print("process") - module_usecase = self.get_module_usecase() + self.sv_input_names = ["usecase"] + module_usecase = self.inputs["usecase"].sv_get()[0][0] if module_usecase: - self.generate_node(*module_usecase) + try: + module_usecase = self.get_module_usecase() + except: + raise Exception( + f"Couldn't run generate_node(). Module usecase: {module_usecase}" + ) + if '.'.join(module_usecase) != self.current_usecase: + self.generate_node(*module_usecase) + try: + for i in range(0, len(self.inputs)): + input = self.inputs[i].sv_get() + except: + # This occurs when a blender save file is reloaded + self.generate_node(*module_usecase) + self.sv_input_names = [i.name for i in self.inputs] + super().process() # super().process() uses zip_long_repeat() which doesn't take objects like bmesh @@ -85,26 +95,45 @@ class SvIfcApiWIP(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc def generate_node(self, module, usecase): importlib.import_module(f"ifcopenshell.api.{module}.{usecase}") - init_func = getattr(getattr(ifcopenshell.api, module), usecase).Usecase.__init__ - if "settings" in init_func.__code__.co_varnames: - args = list(init_func.__code__.co_consts[3]) - args.insert(0, 'file') - else: - args = ['file'] + local_module = getattr(getattr(ifcopenshell.api, module), usecase) + + node_inputs = {} + if hasattr(local_module.Usecase(local_module), "file"): + node_inputs["file"] = None + node_inputs.update(getattr(local_module.Usecase(local_module), "settings", {})) + # print("node inputs: ", node_inputs) while len(self.inputs) > 1: self.inputs.remove(self.inputs[-1]) + + if node_inputs: + self.tooltip = "" + for name, data in node_inputs.items(): + setattr(SvIfcApiWIP, name, StringProperty(name=name)) + self.inputs.new("SvStringsSocket", name).prop_name = name + if data is not None: + self.tooltip = f"{name} ({data}): {data}\n" + else: + self.tooltip = f"{name}: None\n" + self.tooltip = self.tooltip.strip() + self.current_usecase = '.'.join([module, usecase]) - for name in args: - # print("name type", type(name)) - setattr(SvIfcApiWIP, str(name), StringProperty(name=str(name), update=updateNode)) - self.inputs.new("SvStringsSocket", str(name)) def process_ifc(self, usecase, *setting_values): - if usecase: + + if usecase and setting_values: settings = dict(zip(self.sv_input_names[1:], setting_values)) settings = {k: v for k, v in settings.items() if v != ""} - self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, **settings)]) + try: + if "file" in settings: + file = settings["file"] + settings.pop("file") + self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, file, **settings)]) + else: + self.outputs["file"].sv_set([ifcopenshell.api.run(usecase, **settings)]) + except: + raise Exception(f"Couldn't run usecase.") + diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 6894cd8554..18b8a2112f 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -49,24 +49,13 @@ class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe self.outputs.new("SvVerticesSocket", "representation") def draw_buttons(self, context, layout): - op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Description?" + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Geometric Representation" #op.tooltip = self.tooltip def process(self): - print("Running process...") - - # file file = self.inputs["file"].sv_get()[0][0] - - # blender mesh blender_object = self.inputs["blender_object"].sv_get()[0] - print("blender object: ", blender_object) - - #geometry geometry = blender_object.data - print("geometry: ", geometry) - - #run process_ifc self.process_ifc(file, blender_object, geometry) def process_ifc(self, file, blender_object, geometry): @@ -75,7 +64,6 @@ class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe for context in file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): if context.get_info()["ContextType"] == "Model" and context.get_info()["ContextIdentifier"] == "Body": repr_context= context - print("pop", context) elif context.get_info()["ContextType"] == "Model": repr_context= context except: @@ -84,7 +72,6 @@ class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe ) representation = [ifcopenshell.api.run("geometry.add_representation", file, should_run_listeners=False,blender_object = blender_object, geometry=geometry, context = repr_context)] - print("representation: ", representation) try: self.outputs["file"].sv_set([[file]]) self.outputs["representation"].sv_set([representation]) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 8fa03d9136..59c53a4c4b 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -61,10 +61,9 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper for i in range(0, self.entity_schema.attribute_count()): self.sv_input_names.append(self.entity_schema.attribute_by_index(i).name()) - self.process() + super().process() def generate_inputs(self, ifc_class): - # print("generate_inputs...") while len(self.inputs) > 2: self.inputs.remove(self.inputs[-1]) for i in range(0, self.entity_schema.attribute_count()): @@ -78,7 +77,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper for i in range(0, len(entity)): try: value = attributes[i] - # print("value (attribute[i]): ", value, "|value type: ", type(value)) if isinstance(value, str) and value == "": value = None except: diff --git a/src/ifcsverchok/nodes/ifc/create_project.py b/src/ifcsverchok/nodes/ifc/create_project.py index d96f6c545f..e61ac0697a 100644 --- a/src/ifcsverchok/nodes/ifc/create_project.py +++ b/src/ifcsverchok/nodes/ifc/create_project.py @@ -49,7 +49,6 @@ class SvIfcCreateProject(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe #project name project_name = self.inputs["project_name"].sv_get()[0][0] - print("project name:", project_name) self.process_ifc(file, project_name) diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index 430ed4f711..2e485b1fb6 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -59,22 +59,8 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. def process(self): self.sv_input_names = ["file", "entity"] super().process() - - def process_helper(self): - print("Hello from helper") - sv_inputs_nested = [] - for name in self.sv_input_names: - sv_inputs_nested.append(self.inputs[name].sv_get()) - print(24*"#","\n", "sv_input: ", self.inputs[name].sv_get(), "input type: ", type(self.inputs[name].sv_get()), "\n", "#"*24) - for sv_input_nested in zip_long_repeat(*sv_inputs_nested): - for sv_input in zip_long_repeat(*sv_input_nested): - sv_input = list(sv_input) - print(24*"#","\n", "sv_input post zip_long_repeat: ", sv_input, "input type: ", type(sv_input), "\n", "#"*24) - self.process_ifc(*sv_input) def process_ifc(self, file, entity): - print("process ifc...") - print("entity: ", entity) try: if not entity.is_a("IfcProduct"): return @@ -88,7 +74,7 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. obj = bpy.data.objects.new("IFC Element", mesh) bpy.context.scene.collection.objects.link(obj) except: - print("Entity could not be converted into a shape", entity) + raise Exception("Entity could not be converted into a shape. Entity: {}".format(entity)) def register(): diff --git a/src/ifcsverchok/nodes/ifc/quick_project_setup.py b/src/ifcsverchok/nodes/ifc/quick_project_setup.py index 5292be4c73..fe3bb07450 100644 --- a/src/ifcsverchok/nodes/ifc/quick_project_setup.py +++ b/src/ifcsverchok/nodes/ifc/quick_project_setup.py @@ -64,13 +64,10 @@ class SvIfcQuickProjectSetup(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h def process(self): self.sv_input_names = [i.name for i in self.inputs] - print("inputnames: ", self.sv_input_names) super().process() def process_ifc(self, *setting_values): - print("setting values: ", setting_values) settings = dict(zip(self.sv_input_names, setting_values)) - print("settings: ", settings) settings = {k: v for k, v in settings.items() if v != ""} file = template.create( filename=settings['filename'], From 95b4867432edd6c3d6c9afe1f43ae601e34b13a5 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Thu, 8 Sep 2022 01:18:20 +0200 Subject: [PATCH 05/21] created new singleton class SvIfcStore, created new 'create_entity2' node --- src/ifcsverchok/__init__.py | 20 +++-- src/ifcsverchok/ifcstore.py | 96 +++++++++++++++++++++ src/ifcsverchok/nodes/ifc/create_entity2.py | 86 ++++++++++++++++++ 3 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 src/ifcsverchok/ifcstore.py create mode 100644 src/ifcsverchok/nodes/ifc/create_entity2.py diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 1eaca6b5df..e332afbd03 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -1,4 +1,3 @@ - # IfcSverchok - IFC Sverchok extension # Copyright (C) 2020, 2021 Dion Moult # @@ -36,7 +35,10 @@ import sverchok from sverchok.core import sv_registration_utils, make_node_list from sverchok.utils import auto_gather_node_classes, get_node_class_reference from sverchok.menu import SverchNodeItem, SverchNodeCategory, register_node_panels -from sverchok.utils.extra_categories import register_extra_category_provider, unregister_extra_category_provider +from sverchok.utils.extra_categories import ( + register_extra_category_provider, + unregister_extra_category_provider, +) from sverchok.ui.nodeview_space_menu import make_extra_category_menus from sverchok.utils.logging import info, debug @@ -50,6 +52,7 @@ def nodes_index(): ("ifc.read_file", "SvIfcReadFile"), ("ifc.write_file", "SvIfcWriteFile"), ("ifc.create_entity", "SvIfcCreateEntity"), + ("ifc.create_entity2", "SvIfcCreateEntity2"), ("ifc.create_shape", "SvIfcCreateShape"), ("ifc.read_entity", "SvIfcReadEntity"), ("ifc.by_id", "SvIfcById"), @@ -63,8 +66,10 @@ def nodes_index(): ("ifc.get_attribute", "SvIfcGetAttribute"), ("ifc.select_blender_objects", "SvIfcSelectBlenderObjects"), ("ifc.api", "SvIfcApi"), + ("ifc.api_WIP", "SvIfcApiWIP"), ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), ("ifc.create_project", "SvIfcCreateProject"), + ("ifc.quick_project_setup", "SvIfcQuickProjectSetup") ], ) @@ -112,7 +117,10 @@ def make_menu(): nodetype = item[1] rna = get_node_class_reference(nodetype) if not rna: - info("Node `%s' is not available (probably due to missing dependencies).", nodetype) + info( + "Node `%s' is not available (probably due to missing dependencies).", + nodetype, + ) else: node_item = SverchNodeItem.new(nodetype) node_items.append(node_item) @@ -144,7 +152,9 @@ def register(): auto_gather_node_classes(extra_nodes) menu = make_menu() menu_category_provider = SvExCategoryProvider("IFCSVERCHOK", menu) - register_extra_category_provider(menu_category_provider) # if 'IFCSVERCHOK' in nodeitems_utils._node_categories: + register_extra_category_provider( + menu_category_provider + ) # if 'IFCSVERCHOK' in nodeitems_utils._node_categories: nodeitems_utils.register_node_categories("IFCSVERCHOK", menu) our_menu_classes = make_extra_category_menus() @@ -160,4 +170,4 @@ def unregister(): print("Can't unregister menu class %s" % clazz) print(e) unregister_extra_category_provider("IFCSVERCHOK") - unregister_nodes() \ No newline at end of file + unregister_nodes() diff --git a/src/ifcsverchok/ifcstore.py b/src/ifcsverchok/ifcstore.py new file mode 100644 index 0000000000..cc0303165b --- /dev/null +++ b/src/ifcsverchok/ifcstore.py @@ -0,0 +1,96 @@ +# import os +import bpy +# import uuid +# import hashlib +# import zipfile +# import tempfile +import ifcopenshell +from ifcopenshell import template +# import blenderbim.bim.handler +# from pathlib import Path + +class SvIfcStore: + path = "" + file = None + schema = None + cache = None + cache_path = None + id_map = {} + guid_map = {} + deleted_ids = set() + edited_objs = set() + pset_template_path = "" + pset_template_file = None + library_path = "" + library_file = None + element_listeners = set() + undo_redo_stack_objects = set() + undo_redo_stack_object_names = {} + current_transaction = "" + last_transaction = "" + history = [] + future = [] + schema_identifiers = ["IFC4", "IFC2X3"] + + @staticmethod + def purge(): + SvIfcStore.path = "" + SvIfcStore.file = None + SvIfcStore.schema = None + SvIfcStore.cache = None + SvIfcStore.cache_path = None + SvIfcStore.id_map = {} + SvIfcStore.guid_map = {} + SvIfcStore.deleted_ids = set() + SvIfcStore.edited_objs = set() + SvIfcStore.pset_template_path = "" + SvIfcStore.pset_template_file = None + SvIfcStore.library_path = "" + SvIfcStore.library_file = None + SvIfcStore.last_transaction = "" + SvIfcStore.history = [] + SvIfcStore.future = [] + SvIfcStore.schema_identifiers = ["IFC4", "IFC2X3"] + + + @staticmethod + def create_boilerplate(): + + file = template.create( + filename="IfcSverchokDemoFile", + organization=None, + creator=None, + project_name="IfcSverchokDemoProject", + ) + if bpy.context.scene.unit_settings.system == 'IMPERIAL': + #TODO change units to imperial + pass + model = ifcopenshell.api.run("context.add_context", file, context_type="Model") + context = ifcopenshell.api.run( + "context.add_context", + file, + context_type="Model", + context_identifier="Body", + target_view="MODEL_VIEW", + parent=model, + ) + site = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site") + building = ifcopenshell.api.run( + "root.create_entity", file, ifc_class="IfcBuilding", name="My Building" + ) + building_storey = ifcopenshell.api.run( + "root.create_entity", file, ifc_class="IfcBuildingStorey", name="My Storey" + ) + + ifcopenshell.api.run("aggregate.assign_object", file, product=site, relating_object=file.by_type("IfcProject")[0]) + ifcopenshell.api.run("aggregate.assign_object", file, product=building, relating_object=site) + ifcopenshell.api.run("aggregate.assign_object", file, product=building_storey, relating_object=building) + + SvIfcStore.file = file + return SvIfcStore.file + + + + @staticmethod + def get_file(): + return SvIfcStore.file diff --git a/src/ifcsverchok/nodes/ifc/create_entity2.py b/src/ifcsverchok/nodes/ifc/create_entity2.py new file mode 100644 index 0000000000..112d21cd75 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/create_entity2.py @@ -0,0 +1,86 @@ +import bpy +# from helper import SayHello +import ifcopenshell +import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore +# import ifcsverchok.ifc_store +# from bpy.props import StringProperty +# from sverchok.node_tree import SverchCustomTreeNode +# from sverchok.data_structure import updateNode + +import bpy +import ifcopenshell + +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +class SvIfcCreateEntity2(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcCreateEntity2" + bl_label = "IFC Create Entity2" + Name: StringProperty(name="Name", update=updateNode) + Description: StringProperty(name="Description", update=updateNode) + ifc_class: StringProperty(name="ifc_class", update=updateNode) + representation: StringProperty(name="representation", update=updateNode) + + def sv_init(self, context): + self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" + self.inputs.new("SvTextSocket", "Description").prop_name = "Description" + self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "ifc_class" + self.inputs.new("SvStringsSocket", "Representation").prop_name = "representation" + self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "file") #only for testing + + def process(self): + if not any(socket.is_linked for socket in self.outputs): + return + + name = self.inputs["Name"].sv_get()[0][0] + description = self.inputs['Description'].sv_get()[0][0] + ifc_class = self.inputs['IfcClass'].sv_get()[0][0] + representation = self.inputs['Representation'].sv_get()[0][0] + + if SvIfcStore.file is None: + self.file = SvIfcStore.create_boilerplate() + + else: + self.file = SvIfcStore.get_file() + + print("file: " , self.file) + + if self.node_id not in SvIfcStore.id_map.values(): + self.process_ifc(name, description, ifc_class, representation) + else: + entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] + self.entity = self.file.by_id(entity_id) + self.entity.Name = name + self.entity.Description = description + self.entity.Representation = representation + + SvIfcStore.file = self.file + self.outputs["entity"].sv_set([[self.entity]]) + self.outputs["file"].sv_set([[self.file]]) #only for testing + + def process_ifc(self, name, description, ifc_class, representation): + + data = { + 'GlobalId': ifcopenshell.guid.new(), + 'Name': name, + 'Description': description, + 'Representation': representation + + } + self.entity = self.file.create_entity(str(ifc_class), **data) + print("entity: ", self.entity) + SvIfcStore.id_map[self.entity.id()] = self.node_id + print("id_map: ", SvIfcStore.id_map) + + +def register(): + bpy.utils.register_class(SvIfcCreateEntity2) + + +def unregister(): + bpy.utils.unregister_class(SvIfcCreateEntity2) + SvIfcStore.purge() From 532502a4a3c8ad158b956e30894548f7cad66636 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Fri, 9 Sep 2022 09:01:01 +0200 Subject: [PATCH 06/21] new nodes, and changes to create_entity2, but not working yet --- src/ifcsverchok/__init__.py | 3 + src/ifcsverchok/ifcstore.py | 2 + src/ifcsverchok/nodes/ifc/add_pset.py | 75 ++++++++ .../nodes/ifc/add_spatial_element.py | 81 +++++++++ src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 2 +- src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py | 166 ++++++++++++++++++ src/ifcsverchok/nodes/ifc/create_entity2.py | 63 ++++--- 7 files changed, 369 insertions(+), 23 deletions(-) create mode 100644 src/ifcsverchok/nodes/ifc/add_pset.py create mode 100644 src/ifcsverchok/nodes/ifc/add_spatial_element.py create mode 100644 src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index e332afbd03..b9e8b7d4af 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -60,6 +60,8 @@ def nodes_index(): ("ifc.by_type", "SvIfcByType"), ("ifc.by_query", "SvIfcByQuery"), ("ifc.add", "SvIfcAdd"), + ("ifc.add_pset", "SvIfcAddPset"), + ("ifc.add_spatial_element", "SvIfcAddSpatialElement"), ("ifc.remove", "SvIfcRemove"), ("ifc.generate_guid", "SvIfcGenerateGuid"), ("ifc.get_property", "SvIfcGetProperty"), @@ -68,6 +70,7 @@ def nodes_index(): ("ifc.api", "SvIfcApi"), ("ifc.api_WIP", "SvIfcApiWIP"), ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), + ("ifc.bmesh_to_ifc2", "SvIfcBMeshToIfcRepr"), ("ifc.create_project", "SvIfcCreateProject"), ("ifc.quick_project_setup", "SvIfcQuickProjectSetup") diff --git a/src/ifcsverchok/ifcstore.py b/src/ifcsverchok/ifcstore.py index cc0303165b..c334e952fc 100644 --- a/src/ifcsverchok/ifcstore.py +++ b/src/ifcsverchok/ifcstore.py @@ -93,4 +93,6 @@ class SvIfcStore: @staticmethod def get_file(): + if SvIfcStore.file is None: + SvIfcStore.create_boilerplate() return SvIfcStore.file diff --git a/src/ifcsverchok/nodes/ifc/add_pset.py b/src/ifcsverchok/nodes/ifc/add_pset.py new file mode 100644 index 0000000000..bb56caffd1 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/add_pset.py @@ -0,0 +1,75 @@ +import bpy + +import ifcopenshell +import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore + +import bpy +import json +import ifcopenshell + +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +class SvIfcAddPset(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcAddPset" + bl_label = "IFC Add Pset" + Name: StringProperty(name="Name", update=updateNode, default="My_Pset") + Properties: StringProperty(name="Properties", update=updateNode, default="{\"Foo\":\"Bar\"}") + Elements: StringProperty(name="Elements", update=updateNode) + + def sv_init(self, context): + self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" + self.inputs.new("SvTextSocket", "Properties").prop_name = "Properties" + self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" + self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "file") + + def process(self): + if not any(socket.is_linked for socket in self.outputs): + return + + name = self.inputs["Name"].sv_get()[0][0] + properties = self.inputs["Properties"].sv_get()[0][0] + elements = self.inputs["Elements"].sv_get()[0] + + if SvIfcStore.file is None: + SvIfcStore.file = SvIfcStore.create_boilerplate() + self.file = SvIfcStore.get_file() + + if self.node_id not in SvIfcStore.id_map.values(): + element = self.create(name, properties, elements) + else: + element = self.edit(name, properties, elements) + + self.outputs["entity"].sv_set([[element]]) + self.outputs["file"].sv_set([[self.file]]) + + def create(self, name, properties, elements): + results = [] + for element in elements: + result = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name=name) + ifcopenshell.api.run("pset.edit_pset", self.file, pset=result, properties=json.loads(properties)) + SvIfcStore.id_map[result.id()] = self.node_id + results.append(result) + return result + + def edit(self, name, properties, elements): + result = self.get_existing_element() + ifcopenshell.api.run("pset.edit_pset", self.file, pset=result, name=name, properties=json.loads(properties)) + return result + + def get_existing_element(self): + entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] + return self.file.by_id(entity_id) + + +def register(): + bpy.utils.register_class(SvIfcAddPset) + + +def unregister(): + bpy.utils.unregister_class(SvIfcAddPset) + SvIfcStore.purge() diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py new file mode 100644 index 0000000000..3673f5d3de --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -0,0 +1,81 @@ +import bpy + +import ifcopenshell +import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore + +import bpy +import json +import ifcopenshell + +from bpy.props import StringProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcAddSpatialElement" + bl_label = "IFC Add Spatial Element" + Name: StringProperty(name="Name", update=updateNode) + IfcClass: StringProperty(name="IFC Class", update=updateNode, default="IfcSpace") + Elements: StringProperty(name="Elements", update=updateNode) + + def sv_init(self, context): + self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" + self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" + self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" + self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "file") + + def process(self): + if not any(socket.is_linked for socket in self.outputs): + return + + name = self.inputs["Name"].sv_get()[0][0] + ifc_class = self.inputs["IfcClass"].sv_get()[0][0] + elements = self.inputs["Elements"].sv_get()[0] + + if SvIfcStore.file is None: + SvIfcStore.file = SvIfcStore.create_boilerplate() + self.file = SvIfcStore.get_file() + + if self.node_id not in SvIfcStore.id_map.values(): + element = self.create(name, ifc_class, elements) + else: + element = self.edit(name, ifc_class, elements) + + self.outputs["entity"].sv_set([[element]]) + self.outputs["file"].sv_set([[self.file]]) + + def create(self, name, ifc_class, elements): + results = [] + result = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class) + for element in elements: + ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=result) + SvIfcStore.id_map[result.id()] = self.node_id + results.append(result) + return result + + def edit(self, name, ifc_class, elements): + result = self.get_existing_element() + subelements = set(ifcopenshell.util.element.get_decomposition(result)) + elements_set = set(elements) + for removed_element in subelements - elements_set: + # Just realised I don't have a spatial.unassign_container, but if so we'd do it here + pass + for added_element in elements_set - subelements: + ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) + return result + + def get_existing_element(self): + entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] + return self.file.by_id(entity_id) + + +def register(): + bpy.utils.register_class(SvIfcAddSpatialElement) + + +def unregister(): + bpy.utils.unregister_class(SvIfcAddSpatialElement) + SvIfcStore.purge() diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 18b8a2112f..bbde010dce 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -34,7 +34,7 @@ class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe Tooltip: Blender mesh to Ifc Geometric Representation """ bl_idname = "SvIfcBMeshToIfcGeo" - bl_label = "IFC Blender Mesh to IFC Geo" + bl_label = "IFC Blender Mesh to IFC Geo (old)" tooltip: StringProperty(name="Tooltip") context_id: bpy.props.IntProperty() diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py new file mode 100644 index 0000000000..f208d3f928 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py @@ -0,0 +1,166 @@ +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcsverchok.helper +import ifcopenshell.api +from ifcsverchok.ifcstore import SvIfcStore +import blenderbim.tool as tool +import blenderbim.core.geometry as core +from bpy.props import StringProperty, EnumProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode +from blenderbim.bim.module.root.prop import get_contexts + + +class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + """ + Triggers: BMesh to Ifc Repr + Tooltip: Blender mesh to Ifc Shape Representation + """ + bl_idname = "SvIfcBMeshToIfcRepr" + bl_label = "IFC Blender Mesh to IFC Repr" + blender_objects: StringProperty(name="Blender Mesh(es)", description="Blender Mesh Object(s)", update=updateNode) + ifc_representation_class: StringProperty(name="Ifc Representation Class", description="Whether to cast a mesh into a particular class", update=updateNode) + + context_types = [ + ('Model', 'Model', 'Context type: Model', 0), + ('Plan', 'Plan', 'Context type: Plan', 1), + ] + + context_identifiers = [ + ('Body', 'Body', 'Context identifier: Body', 0), + ('Annotation', 'Annotation', 'Context identifier: Annotation', 1), + ('Box', 'Box', 'Context identifier: Box', 2), + ('Axis', 'Axis', 'Context identifier: Axis', 3), + ] + target_views = [ + ('MODEL_VIEW', 'MODEL_VIEW', 'Target View: MODEL_VIEW', 0), + ('PLAN_VIEW', 'PLAN_VIEW', 'Target View: PLAN_VIEW', 1), + ('GRAPH_VIEW', 'GRAPH_VIEW', 'Target View: GRAPH_VIEW', 2), + ('SKETCH_VIEW', 'SKETCH_VIEW', 'Target View: SKETCH_VIEW', 3), + ] + paradigms = [ + ('Tessellation', 'Tessellation', 'Geometry paradigm: Tessellation', 0), + ('Extrusion', 'Extrusion', 'Geometry paradigm: Extrusion', 1), + ] + + context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) + context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) + target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) + paradigm: EnumProperty(name="Paradigm", description="Which geometry type to convert to. Choose between tessellation or extrusion. Default: Tessellation.",default="Tessellation",items=paradigms, update=updateNode) + tooltip: StringProperty(name="Tooltip") + context_id: bpy.props.IntProperty() + + def sv_init(self, context): + self.inputs.new("SvObjectSocket", "blender_objects") #no prop for now + self.inputs.new("SvStringsSocket", "ifc_representation_class").prop_name = "ifc_representation_class" + self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" + self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" + self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" + self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" + self.outputs.new("SvVerticesSocket", "file") + self.outputs.new("SvVerticesSocket", "Representation") + + def draw_buttons(self, context, layout): + op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation" + # layout.prop(self, 'context_type', text='') + # layout.prop(self, 'context_identifier', text='') + # layout.prop(self, 'target_view', text='') + # layout.prop(self, 'paradigm', text='') + #op.tooltip = self.tooltip + + def process(self): + # if not self.inputs['blender_objects'].is_linked: + # return + + self.file = SvIfcStore.get_file() + + + self.sv_input_names = [i.name for i in self.inputs] + for i in range(0, len(self.inputs)): + print("self.sv_input_names[i]: ", self.sv_input_names[i]) + print("self.inputs[i].sv_get(): ", self.inputs[i].sv_get()) + if self.sv_input_names[i] != "blender_objects": + setattr(self, self.sv_input_names[i], self.inputs[i].sv_get()) #doesn't work for lists? + + self.blender_objects = self.inputs["blender_object"].sv_get() + self.create_context() + + if self.node_id not in SvIfcStore.id_map.values(): + for blender_object in self.blender_objects: + geometry = blender_object.data + self.process_ifc(self.file, blender_object, geometry) + else: + #TODO: edit existing representation + raise Exception("Editing not yet implemented") + + + SvIfcStore.file = self.file + try: + self.outputs["file"].sv_set([[self.file]]) #only for testing + self.outputs["Representation"].sv_set([self.representation]) + except: + raise Exception( + "Couldn't write to file. Representation: {}".format( + self.representation + ) + ) + + def process_ifc(self, blender_object, geometry): + try: + self.representation = [ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=geometry, context = self.context)] + except: + raise Exception("Couldn't create representation. Representation: {}".format( + self.representation + )) + SvIfcStore.id_map[self.representation.id()] = self.node_id + + def create_context(self): + if self.file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): + for context in self.file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): + if context.get_info()["ContextType"] == "Model" and context.get_info()["ContextIdentifier"] == "Body": + self.context = context + elif context.get_info()["ContextType"] == "Model": + self.context= context + else: + model = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) + self.context = ifcopenshell.api.run( + "context.add_context", + self.file, + context_type=self.context_type, + context_identifier=self.context_identifier, + target_view=self.target_view, + parent=model, + ) + SvIfcStore.id_map[self.context.id()] = self.node_id + + def sv_free(self): + try: + SvIfcStore.id_map.pop(self.representation.id()) + SvIfcStore.id_map.pop(self.context.id()) + except KeyError or AttributeError: + pass + +def register(): + bpy.utils.register_class(SvIfcBMeshToIfcRepr) + + +def unregister(): + bpy.utils.unregister_class(SvIfcBMeshToIfcRepr) diff --git a/src/ifcsverchok/nodes/ifc/create_entity2.py b/src/ifcsverchok/nodes/ifc/create_entity2.py index 112d21cd75..d581814b54 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity2.py +++ b/src/ifcsverchok/nodes/ifc/create_entity2.py @@ -19,44 +19,55 @@ from sverchok.data_structure import updateNode class SvIfcCreateEntity2(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcCreateEntity2" bl_label = "IFC Create Entity2" - Name: StringProperty(name="Name", update=updateNode) - Description: StringProperty(name="Description", update=updateNode) - ifc_class: StringProperty(name="ifc_class", update=updateNode) - representation: StringProperty(name="representation", update=updateNode) + Name: StringProperty(name="Name",default="", update=updateNode) + Description: StringProperty(name="Description", default="", update=updateNode) + ifc_class: StringProperty(name="IfcClass", update=updateNode) + representation: StringProperty(name="representation", default="", update=updateNode) + properties: StringProperty(name="properties", update=updateNode) def sv_init(self, context): self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" - self.inputs.new("SvTextSocket", "Description").prop_name = "Description" + self.inputs.new("SvStringsSocket", "Description").prop_name = "Description" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "ifc_class" self.inputs.new("SvStringsSocket", "Representation").prop_name = "representation" + self.inputs.new("SvStringsSocket", "Properties").prop_name = "properties" self.outputs.new("SvStringsSocket", "entity") self.outputs.new("SvStringsSocket", "file") #only for testing def process(self): - if not any(socket.is_linked for socket in self.outputs): + if not self.inputs['IfcClass'].is_linked: return + self.sv_input_names = [i.name for i in self.inputs] + name = self.inputs["Name"].sv_get()[0][0] description = self.inputs['Description'].sv_get()[0][0] ifc_class = self.inputs['IfcClass'].sv_get()[0][0] - representation = self.inputs['Representation'].sv_get()[0][0] - - if SvIfcStore.file is None: - self.file = SvIfcStore.create_boilerplate() - - else: - self.file = SvIfcStore.get_file() + representation = self.inputs['Representation'].sv_get()[0][0] + self.file = SvIfcStore.get_file() print("file: " , self.file) + print(SvIfcStore.file) if self.node_id not in SvIfcStore.id_map.values(): self.process_ifc(name, description, ifc_class, representation) else: entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] self.entity = self.file.by_id(entity_id) + print(name) self.entity.Name = name self.entity.Description = description - self.entity.Representation = representation + + if representation and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): + ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=representation) + elif representation: + self.entity.Representation = representation + else: + pass + + if self.entity.is_a() != ifc_class: + # This crashes blender + ifcopenshell.util.schema.reassign_class(self.file, self.entity, ifc_class) SvIfcStore.file = self.file self.outputs["entity"].sv_set([[self.entity]]) @@ -64,23 +75,31 @@ class SvIfcCreateEntity2(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe def process_ifc(self, name, description, ifc_class, representation): - data = { - 'GlobalId': ifcopenshell.guid.new(), - 'Name': name, - 'Description': description, - 'Representation': representation + try: + self.entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name, description=description) + if representation: + ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=representation) + except: + raise Exception("Something went wrong. Cannot create entity.") - } - self.entity = self.file.create_entity(str(ifc_class), **data) print("entity: ", self.entity) SvIfcStore.id_map[self.entity.id()] = self.node_id print("id_map: ", SvIfcStore.id_map) + def sv_free(self): + try: + SvIfcStore.id_map.pop(self.entity.id()) + except KeyError or AttributeError: + print("Either KeyError or AttributeError occurred.") + pass + + print("I'm free!") + + def register(): bpy.utils.register_class(SvIfcCreateEntity2) def unregister(): bpy.utils.unregister_class(SvIfcCreateEntity2) - SvIfcStore.purge() From 310cbebba978dcbbe44f8ee06ee293d124db6061 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 10 Oct 2022 09:01:00 +0200 Subject: [PATCH 07/21] fixed create_entity and minor changes to bmesh_to_ifc --- src/ifcsverchok/__init__.py | 2 - .../nodes/ifc/add_spatial_element.py | 3 + src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 238 +++++++++++++---- src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py | 166 ------------ src/ifcsverchok/nodes/ifc/create_entity.py | 240 +++++++++++------- src/ifcsverchok/nodes/ifc/create_entity2.py | 105 -------- 6 files changed, 343 insertions(+), 411 deletions(-) delete mode 100644 src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py delete mode 100644 src/ifcsverchok/nodes/ifc/create_entity2.py diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index b9e8b7d4af..92151487ec 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -52,7 +52,6 @@ def nodes_index(): ("ifc.read_file", "SvIfcReadFile"), ("ifc.write_file", "SvIfcWriteFile"), ("ifc.create_entity", "SvIfcCreateEntity"), - ("ifc.create_entity2", "SvIfcCreateEntity2"), ("ifc.create_shape", "SvIfcCreateShape"), ("ifc.read_entity", "SvIfcReadEntity"), ("ifc.by_id", "SvIfcById"), @@ -70,7 +69,6 @@ def nodes_index(): ("ifc.api", "SvIfcApi"), ("ifc.api_WIP", "SvIfcApiWIP"), ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), - ("ifc.bmesh_to_ifc2", "SvIfcBMeshToIfcRepr"), ("ifc.create_project", "SvIfcCreateProject"), ("ifc.quick_project_setup", "SvIfcQuickProjectSetup") diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index 3673f5d3de..1f79bf4ed1 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -60,6 +60,9 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h result = self.get_existing_element() subelements = set(ifcopenshell.util.element.get_decomposition(result)) elements_set = set(elements) + print("RESULT: ", result) + print("subelements: ", subelements) + print("elements_set: ", elements_set) for removed_element in subelements - elements_set: # Just realised I don't have a spatial.unassign_container, but if so we'd do it here pass diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index bbde010dce..76736ad2f7 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -16,76 +16,220 @@ # You should have received a copy of the GNU General Public License # along with IfcSverchok. If not, see . +from copy import deepcopy +from email.policy import default import bpy import ifcopenshell import ifcsverchok.helper import ifcopenshell.api +from ifcsverchok.ifcstore import SvIfcStore import blenderbim.tool as tool import blenderbim.core.geometry as core -from bpy.props import StringProperty +from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty, PointerProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import (updateNode, flatten_data, fixed_iter, flat_iter) from blenderbim.bim.module.root.prop import get_contexts +from sverchok.data_structure import zip_long_repeat, node_id +from sverchok.core.socket_data import sv_get_socket +from itertools import chain, cycle -class SvIfcBMeshToIfcGeo(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): +class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): """ - Triggers: BMesh to Ifc Geo - Tooltip: Blender mesh to Ifc Geometric Representation + Triggers: BMesh to Ifc Repr + Tooltip: Blender mesh to Ifc Shape Representation """ - bl_idname = "SvIfcBMeshToIfcGeo" - bl_label = "IFC Blender Mesh to IFC Geo (old)" + bl_idname = "SvIfcBMeshToIfcRepr" + bl_label = "IFC Blender Mesh to IFC Repr" + node_dict = {} + + is_scene_dependent = True # if True and is_interactive then the node will be updated upon scene changes + + def refresh_node(self, context): + if self.refresh_local: + self.process() + self.refresh_local = False + + refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) + + n_id: StringProperty() + context_types = [ + ('Model', 'Model', 'Context type: Model', 0), + ('Plan', 'Plan', 'Context type: Plan', 1), + ] + + context_identifiers = [ + ('Body', 'Body', 'Context identifier: Body', 0), + ('Annotation', 'Annotation', 'Context identifier: Annotation', 1), + ('Box', 'Box', 'Context identifier: Box', 2), + ('Axis', 'Axis', 'Context identifier: Axis', 3), + ] + target_views = [ + ('MODEL_VIEW', 'MODEL_VIEW', 'Target View: MODEL_VIEW', 0), + ('PLAN_VIEW', 'PLAN_VIEW', 'Target View: PLAN_VIEW', 1), + ('GRAPH_VIEW', 'GRAPH_VIEW', 'Target View: GRAPH_VIEW', 2), + ('SKETCH_VIEW', 'SKETCH_VIEW', 'Target View: SKETCH_VIEW', 3), + ] + paradigms = [ + ('Tessellation', 'Tessellation', 'Geometry paradigm: Tessellation', 0), + ('Extrusion', 'Extrusion', 'Geometry paradigm: Extrusion', 1), + ] + blender_objects: PointerProperty(name="Blender Mesh(es)", description="Blender Mesh Object(s)",update=updateNode, type=bpy.types.Object) + context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) + context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) + target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) + paradigm: EnumProperty(name="Paradigm", description="Which geometry type to convert to. Choose between tessellation or extrusion. Default: Tessellation.",default="Tessellation",items=paradigms, update=updateNode) tooltip: StringProperty(name="Tooltip") - context_id: bpy.props.IntProperty() + def sv_init(self, context): - input_socket = self.inputs.new("SvStringsSocket", "file") - input_socket.tooltip = "ifc file to add the geometry to" - input_socket = self.inputs.new("SvObjectSocket", "blender_object") - input_socket.tooltip = "Pick or pass Blender Mesh object" - input_socket = self.inputs.new("SvStringsSocket", "ifc_representation_class") - input_socket.tooltip = "Whether to cast a mesh into a particular class" + self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" + self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" + self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" + self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" + self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" #no prop for now self.outputs.new("SvVerticesSocket", "file") - self.outputs.new("SvVerticesSocket", "representation") - + self.outputs.new("SvVerticesSocket", "Representations") + self.width = 210 + self.node_dict[hash(self)] = {} + + def draw_buttons(self, context, layout): - op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Geometric Representation" - #op.tooltip = self.tooltip + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation" + + row = layout.row(align=True) + row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) + row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - file = self.inputs["file"].sv_get()[0][0] - blender_object = self.inputs["blender_object"].sv_get()[0] - geometry = blender_object.data - self.process_ifc(file, blender_object, geometry) - - def process_ifc(self, file, blender_object, geometry): - #get context - try: - for context in file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): - if context.get_info()["ContextType"] == "Model" and context.get_info()["ContextIdentifier"] == "Body": - repr_context= context - elif context.get_info()["ContextType"] == "Model": - repr_context= context - except: - raise Exception( - "Ifc Geometric Representation Context is missing." - ) + print("#"*20, "\n running bmesh_to_ifc3 PROCESS()... \n", "#"*20,) + print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - representation = [ifcopenshell.api.run("geometry.add_representation", file, should_run_listeners=False,blender_object = blender_object, geometry=geometry, context = repr_context)] - try: - self.outputs["file"].sv_set([[file]]) - self.outputs["representation"].sv_set([representation]) - except: - raise Exception( - "Couldn't write to file. Representation: {}".format( - representation - ) - ) + self.sv_input_names = [i.name for i in self.inputs] + if hash(self) not in self.node_dict: + self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict[hash(self)]: + self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + + print("node_dict: ", self.node_dict) + if not self.inputs["blender_objects"].sv_get()[0]: + return + edit = False + for i in range(len(self.inputs)): + input = self.inputs[i].sv_get(deepcopy=False) + # print("input: ", input) + # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) + if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: + edit = True + self.node_dict[hash(self)][self.inputs[i].name] = input + + #temporary + if self.paradigm == "Extrusion": + raise Exception("Extrusion not yet implemented.") + return + + if self.refresh_local: + edit = True + + blender_objects = self.inputs["blender_objects"].sv_get() + # print("\ncontext_type: ", self.context_type) + # print("context_identifier: ", self.context_identifier) + # print("blender_objects: ", blender_objects) + + self.file = SvIfcStore.get_file() + + self.context = self.get_context() + if self.node_id not in SvIfcStore.id_map: + representations = self.create(blender_objects) + else: + if edit is True: + self.edit() + representations = self.create(blender_objects) + else: + representations = self.get_existing_element() + + print("representations: ", representations) + print("SvIfcStore.id_map: ", SvIfcStore.id_map) + + self.outputs["Representations"].sv_set(representations) + self.outputs["file"].sv_set([[self.file]]) + + def create(self, blender_objects): + results = [] + for blender_object in blender_objects: + representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.context) + if not representation: + raise Exception("Couldn't create representation. Possibly wrong context.") + results.append([representation]) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) + return results + + def edit(self): + # results = self.get_existing_element() + if "Representations" not in SvIfcStore.id_map[self.node_id]: + return + for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: + #if self.file.by_id(step_id).is_a('IfcShapeRepresentation'): + print("step_id: ", step_id) + ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) + del SvIfcStore.id_map[self.node_id]["Representations"] + return + + def get_existing_element(self): + results = [] + for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: + results.append([self.file.by_id(step_id)]) + return results + + def get_context(self): + context = ifcopenshell.util.representation.get_context(self.file, self.context_type, self.context_identifier, self.target_view) + + if not context: + parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) + if not parent: + parent = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) + print("\nParent: ", parent) + context = ifcopenshell.api.run( + "context.add_context", + self.file, + context_type=self.context_type, + context_identifier=self.context_identifier, + target_view=self.target_view, + parent=parent, + ) + # SvIfcStore.id_map.setdefault(self.node_id, []).append(context.id()) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) + + return context + + def sv_free(self): + + try: + print('DELETING') + self.file = SvIfcStore.get_file() + if "Representations" in SvIfcStore.id_map[self.node_id]: + for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: + print("step_id: ", step_id) + ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) + + if "Contexts" in SvIfcStore.id_map[self.node_id]: + for context_id in SvIfcStore.id_map[self.node_id]["Contexts"]: + if not self.file.get_inverse(self.file.by_id(self.context.id())): + ifcopenshell.api.run("context.remove_context", self.file, representation=self.file.by_id(context_id)) + print("Removed context with step ID: ", context_id) + SvIfcStore.id_map[self.node_id]["Contexts"].remove(context_id) + del SvIfcStore.id_map[self.node_id] + del self.node_dict[hash(self)] + print('Node was deleted') + except KeyError or AttributeError: + pass + def register(): - bpy.utils.register_class(SvIfcBMeshToIfcGeo) + bpy.utils.register_class(SvIfcBMeshToIfcRepr) + def unregister(): - bpy.utils.unregister_class(SvIfcBMeshToIfcGeo) + bpy.utils.unregister_class(SvIfcBMeshToIfcRepr) \ No newline at end of file diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py deleted file mode 100644 index f208d3f928..0000000000 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc2.py +++ /dev/null @@ -1,166 +0,0 @@ -# IfcSverchok - IFC Sverchok extension -# Copyright (C) 2020, 2021 Dion Moult -# -# 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 . - -import bpy -import ifcopenshell -import ifcsverchok.helper -import ifcopenshell.api -from ifcsverchok.ifcstore import SvIfcStore -import blenderbim.tool as tool -import blenderbim.core.geometry as core -from bpy.props import StringProperty, EnumProperty -from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode -from blenderbim.bim.module.root.prop import get_contexts - - -class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): - """ - Triggers: BMesh to Ifc Repr - Tooltip: Blender mesh to Ifc Shape Representation - """ - bl_idname = "SvIfcBMeshToIfcRepr" - bl_label = "IFC Blender Mesh to IFC Repr" - blender_objects: StringProperty(name="Blender Mesh(es)", description="Blender Mesh Object(s)", update=updateNode) - ifc_representation_class: StringProperty(name="Ifc Representation Class", description="Whether to cast a mesh into a particular class", update=updateNode) - - context_types = [ - ('Model', 'Model', 'Context type: Model', 0), - ('Plan', 'Plan', 'Context type: Plan', 1), - ] - - context_identifiers = [ - ('Body', 'Body', 'Context identifier: Body', 0), - ('Annotation', 'Annotation', 'Context identifier: Annotation', 1), - ('Box', 'Box', 'Context identifier: Box', 2), - ('Axis', 'Axis', 'Context identifier: Axis', 3), - ] - target_views = [ - ('MODEL_VIEW', 'MODEL_VIEW', 'Target View: MODEL_VIEW', 0), - ('PLAN_VIEW', 'PLAN_VIEW', 'Target View: PLAN_VIEW', 1), - ('GRAPH_VIEW', 'GRAPH_VIEW', 'Target View: GRAPH_VIEW', 2), - ('SKETCH_VIEW', 'SKETCH_VIEW', 'Target View: SKETCH_VIEW', 3), - ] - paradigms = [ - ('Tessellation', 'Tessellation', 'Geometry paradigm: Tessellation', 0), - ('Extrusion', 'Extrusion', 'Geometry paradigm: Extrusion', 1), - ] - - context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) - context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) - target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) - paradigm: EnumProperty(name="Paradigm", description="Which geometry type to convert to. Choose between tessellation or extrusion. Default: Tessellation.",default="Tessellation",items=paradigms, update=updateNode) - tooltip: StringProperty(name="Tooltip") - context_id: bpy.props.IntProperty() - - def sv_init(self, context): - self.inputs.new("SvObjectSocket", "blender_objects") #no prop for now - self.inputs.new("SvStringsSocket", "ifc_representation_class").prop_name = "ifc_representation_class" - self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" - self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" - self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" - self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" - self.outputs.new("SvVerticesSocket", "file") - self.outputs.new("SvVerticesSocket", "Representation") - - def draw_buttons(self, context, layout): - op = layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation" - # layout.prop(self, 'context_type', text='') - # layout.prop(self, 'context_identifier', text='') - # layout.prop(self, 'target_view', text='') - # layout.prop(self, 'paradigm', text='') - #op.tooltip = self.tooltip - - def process(self): - # if not self.inputs['blender_objects'].is_linked: - # return - - self.file = SvIfcStore.get_file() - - - self.sv_input_names = [i.name for i in self.inputs] - for i in range(0, len(self.inputs)): - print("self.sv_input_names[i]: ", self.sv_input_names[i]) - print("self.inputs[i].sv_get(): ", self.inputs[i].sv_get()) - if self.sv_input_names[i] != "blender_objects": - setattr(self, self.sv_input_names[i], self.inputs[i].sv_get()) #doesn't work for lists? - - self.blender_objects = self.inputs["blender_object"].sv_get() - self.create_context() - - if self.node_id not in SvIfcStore.id_map.values(): - for blender_object in self.blender_objects: - geometry = blender_object.data - self.process_ifc(self.file, blender_object, geometry) - else: - #TODO: edit existing representation - raise Exception("Editing not yet implemented") - - - SvIfcStore.file = self.file - try: - self.outputs["file"].sv_set([[self.file]]) #only for testing - self.outputs["Representation"].sv_set([self.representation]) - except: - raise Exception( - "Couldn't write to file. Representation: {}".format( - self.representation - ) - ) - - def process_ifc(self, blender_object, geometry): - try: - self.representation = [ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=geometry, context = self.context)] - except: - raise Exception("Couldn't create representation. Representation: {}".format( - self.representation - )) - SvIfcStore.id_map[self.representation.id()] = self.node_id - - def create_context(self): - if self.file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): - for context in self.file.by_type("IFCGEOMETRICREPRESENTATIONCONTEXT", include_subtypes=True): - if context.get_info()["ContextType"] == "Model" and context.get_info()["ContextIdentifier"] == "Body": - self.context = context - elif context.get_info()["ContextType"] == "Model": - self.context= context - else: - model = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) - self.context = ifcopenshell.api.run( - "context.add_context", - self.file, - context_type=self.context_type, - context_identifier=self.context_identifier, - target_view=self.target_view, - parent=model, - ) - SvIfcStore.id_map[self.context.id()] = self.node_id - - def sv_free(self): - try: - SvIfcStore.id_map.pop(self.representation.id()) - SvIfcStore.id_map.pop(self.context.id()) - except KeyError or AttributeError: - pass - -def register(): - bpy.utils.register_class(SvIfcBMeshToIfcRepr) - - -def unregister(): - bpy.utils.unregister_class(SvIfcBMeshToIfcRepr) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 59c53a4c4b..795503bc81 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -1,115 +1,173 @@ +import bpy -# IfcSverchok - IFC Sverchok extension -# Copyright (C) 2020, 2021 Dion Moult -# -# 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 . +# from helper import SayHello +import ifcopenshell +import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore + +# import ifcsverchok.ifc_store +# from bpy.props import StringProperty +# from sverchok.node_tree import SverchCustomTreeNode +# from sverchok.data_structure import updateNode import bpy import ifcopenshell -import ifcsverchok.helper -from bpy.props import StringProperty + +from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty, PointerProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_length + +input_map = {} class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcCreateEntity" bl_label = "IFC Create Entity" - file: StringProperty(name="file", update=updateNode) - ifc_class: StringProperty(name="ifc_class", update=updateNode) - current_ifc_class: StringProperty(name="current_ifc_class") + node_dict = {} + + is_scene_dependent = True # if True and is_interactive then the node will be updated upon scene changes + + def refresh_node(self, context): + if self.refresh_local: + self.process() + self.refresh_local = False + + refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) + + Names: StringProperty(name="Names", default="", update=updateNode) + Descriptions: StringProperty(name="Descriptions", default="", update=updateNode) + IfcClass: StringProperty(name="IfcClass", update=updateNode) + Representations: StringProperty(name="Representations", default="", update=updateNode) + Properties: StringProperty(name="properties", update=updateNode) def sv_init(self, context): - self.inputs.new("SvStringsSocket", "file").prop_name = "file" - self.inputs.new("SvStringsSocket", "ifc_class").prop_name = "ifc_class" - self.outputs.new("SvStringsSocket", "file") - self.outputs.new("SvStringsSocket", "entity") + self.inputs.new("SvStringsSocket", "Names").prop_name = "Names" + self.inputs.new("SvStringsSocket", "Descriptions").prop_name = "Descriptions" + self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" + self.inputs.new("SvStringsSocket", "Representations").prop_name = "Representations" + self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" + self.outputs.new("SvStringsSocket", "Entities") + self.outputs.new("SvStringsSocket", "file") # only for testing + self.node_dict[hash(self)] = {} def process(self): - self.sv_input_names = ["file", "ifc_class"] - ifc_class = self.inputs["ifc_class"].sv_get()[0][0] - if ifc_class: - file = self.inputs["file"].sv_get()[0][0] - if file: - schema_name = file.wrapped_data.schema - else: - schema_name = "IFC4" - self.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(schema_name) - self.entity_schema = self.schema.declaration_by_name(ifc_class) + print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) + print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - if ifc_class != self.current_ifc_class: - self.generate_inputs(ifc_class) - try: - for i in range(0, len(self.inputs)): - input = self.inputs[i].sv_get() - except: - # This occurs when a blender save file is reloaded - self.generate_inputs(ifc_class) - - for i in range(0, self.entity_schema.attribute_count()): - self.sv_input_names.append(self.entity_schema.attribute_by_index(i).name()) - super().process() + self.names = self.inputs["Names"].sv_get() + self.descriptions = self.inputs["Descriptions"].sv_get() + self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] + self.representations = self.inputs["Representations"].sv_get() + self.properties = self.inputs["Properties"].sv_get() - def generate_inputs(self, ifc_class): - while len(self.inputs) > 2: - self.inputs.remove(self.inputs[-1]) - for i in range(0, self.entity_schema.attribute_count()): - name = self.entity_schema.attribute_by_index(i).name() - setattr(SvIfcCreateEntity, name, StringProperty(name=name)) - self.inputs.new("SvStringsSocket", name).prop_name = name - self.current_ifc_class = ifc_class - def process_ifc(self, file, ifc_class, *attributes): - entity = file.create_entity(ifc_class) - for i in range(0, len(entity)): + self.sv_input_names = [i.name for i in self.inputs] + + if hash(self) not in self.node_dict: + self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict[hash(self)]: + self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + print("node_dict: ", self.node_dict) + if not self.inputs["IfcClass"].sv_get()[0][0]: + raise Exception("Insert IfcClass") + return + + edit = False + for i in range(len(self.inputs)): + input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False) + # print("input: ", input) + # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) + if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: + edit = True + self.node_dict[hash(self)][self.inputs[i].name] = input + + if self.refresh_local: + edit = True + + + self.names = repeat_last_for_length(self.names, len(self.representations), deepcopy=False) + self.descriptions = repeat_last_for_length(self.descriptions, len(self.representations), deepcopy=False) + # print("REPRESENTATION: ", self.representations) + # print("IfcClass: ",self.ifc_class) + print("Names: ",self.names) + print("Descriptions: ",self.descriptions) + + + + self.file = SvIfcStore.get_file() + + if self.node_id not in SvIfcStore.id_map: + enities = self.create() + else: + if edit is True: + enities = self.edit() + else: + enities = self.get_existing_element() + + print("Entities: ", enities) + print("SvIfcStore.id_map: ", SvIfcStore.id_map) + + self.outputs["Entities"].sv_set(enities) + self.outputs["file"].sv_set([[self.file]]) + + def create(self): + # print("#"*20, "\n running create entity CREATE()... \n") + results = [] + for i, name in enumerate(self.names): + print(type(self.names[i][0])) try: - value = attributes[i] - if isinstance(value, str) and value == "": - value = None - except: - value = None - if value is None and entity.is_a("IfcRoot") and i == 0: - value = ifcopenshell.guid.new() - if value is not None and entity.attribute_name(i) == "Representation": - value = file.createIfcProductDefinitionShape(None, None, Representations = [value]) - #product_shape = ifcopenshell.api.run("geometry.assign_representation", file, product = , representation = value) - if value is not None: - value = self.cast_value(self.entity_schema.attribute_by_index(i), value) - try: - entity[i] = value - except: - raise Exception( - "The IFC class {} requires a valid value for {} - you provided {}".format( - ifc_class, entity.attribute_name(i), value - ) - ) + self.entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.ifc_class, name=self.names[i][0], description=self.descriptions[i][0]) + try: + ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=self.representations[i][0]) + except IndexError: + pass + results.append([self.entity]) + SvIfcStore.id_map.setdefault(self.node_id, []).append(self.entity.id()) + except: + raise Exception("Something went wrong. Cannot create entity.") + return results + + def edit(self): + results = [] + id_map_copy = SvIfcStore.id_map[self.node_id].copy() + for i, step_id in enumerate(id_map_copy): + self.entity = self.file.by_id(step_id) + self.entity.Name = self.names[i][0] + self.entity.Description = self.descriptions[i][0] + + if self.representations[i][0] and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): + ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=self.representations[i][0]) + elif self.representations[i][0]: + self.entity.Representation = self.representations[i][0] + else: + pass - self.outputs["file"].sv_set([[file]]) - self.outputs["entity"].sv_set([[entity]]) + if self.entity.is_a() != self.ifc_class: + SvIfcStore.id_map[self.node_id].remove(step_id) + self.entity = ifcopenshell.util.schema.reassign_class(self.file, self.entity, self.ifc_class) + SvIfcStore.id_map.setdefault(self.node_id, []).append(self.entity.id()) + results.append([self.entity]) - def cast_value(self, attribute, value): - data_type = self.get_attribute_data_type(attribute.type_of_attribute()) - if data_type == "integer": - value = int(value) - return value + return results - def get_attribute_data_type(self, data_type): - if hasattr(data_type, "declared_type"): - return self.get_attribute_data_type(data_type.declared_type()) - return data_type + def get_existing_element(self): + # print("#"*20, "\n running create entity get_existing_element()... \n", "#"*20,) + results = [] + for i, step_id in enumerate(SvIfcStore.id_map[self.node_id]): + self.entity = self.file.by_id(step_id) + results.append([self.entity]) + return results + + + def sv_free(self): + + try: + print('DELETING') + del SvIfcStore.id_map[self.node_id] + del self.node_dict[hash(self)] + print('Node was deleted') + except KeyError or AttributeError: + pass def register(): diff --git a/src/ifcsverchok/nodes/ifc/create_entity2.py b/src/ifcsverchok/nodes/ifc/create_entity2.py deleted file mode 100644 index d581814b54..0000000000 --- a/src/ifcsverchok/nodes/ifc/create_entity2.py +++ /dev/null @@ -1,105 +0,0 @@ -import bpy -# from helper import SayHello -import ifcopenshell -import ifcsverchok.helper -from ifcsverchok.ifcstore import SvIfcStore -# import ifcsverchok.ifc_store -# from bpy.props import StringProperty -# from sverchok.node_tree import SverchCustomTreeNode -# from sverchok.data_structure import updateNode - -import bpy -import ifcopenshell - -from bpy.props import StringProperty -from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode - - -class SvIfcCreateEntity2(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): - bl_idname = "SvIfcCreateEntity2" - bl_label = "IFC Create Entity2" - Name: StringProperty(name="Name",default="", update=updateNode) - Description: StringProperty(name="Description", default="", update=updateNode) - ifc_class: StringProperty(name="IfcClass", update=updateNode) - representation: StringProperty(name="representation", default="", update=updateNode) - properties: StringProperty(name="properties", update=updateNode) - - def sv_init(self, context): - self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" - self.inputs.new("SvStringsSocket", "Description").prop_name = "Description" - self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "ifc_class" - self.inputs.new("SvStringsSocket", "Representation").prop_name = "representation" - self.inputs.new("SvStringsSocket", "Properties").prop_name = "properties" - self.outputs.new("SvStringsSocket", "entity") - self.outputs.new("SvStringsSocket", "file") #only for testing - - def process(self): - if not self.inputs['IfcClass'].is_linked: - return - - self.sv_input_names = [i.name for i in self.inputs] - - name = self.inputs["Name"].sv_get()[0][0] - description = self.inputs['Description'].sv_get()[0][0] - ifc_class = self.inputs['IfcClass'].sv_get()[0][0] - representation = self.inputs['Representation'].sv_get()[0][0] - - self.file = SvIfcStore.get_file() - print("file: " , self.file) - print(SvIfcStore.file) - - if self.node_id not in SvIfcStore.id_map.values(): - self.process_ifc(name, description, ifc_class, representation) - else: - entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] - self.entity = self.file.by_id(entity_id) - print(name) - self.entity.Name = name - self.entity.Description = description - - if representation and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): - ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=representation) - elif representation: - self.entity.Representation = representation - else: - pass - - if self.entity.is_a() != ifc_class: - # This crashes blender - ifcopenshell.util.schema.reassign_class(self.file, self.entity, ifc_class) - - SvIfcStore.file = self.file - self.outputs["entity"].sv_set([[self.entity]]) - self.outputs["file"].sv_set([[self.file]]) #only for testing - - def process_ifc(self, name, description, ifc_class, representation): - - try: - self.entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name, description=description) - if representation: - ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=representation) - except: - raise Exception("Something went wrong. Cannot create entity.") - - print("entity: ", self.entity) - SvIfcStore.id_map[self.entity.id()] = self.node_id - print("id_map: ", SvIfcStore.id_map) - - - def sv_free(self): - try: - SvIfcStore.id_map.pop(self.entity.id()) - except KeyError or AttributeError: - print("Either KeyError or AttributeError occurred.") - pass - - print("I'm free!") - - -def register(): - bpy.utils.register_class(SvIfcCreateEntity2) - - -def unregister(): - bpy.utils.unregister_class(SvIfcCreateEntity2) From 93b92dca9dbb572f56b397a17ece7dea6178d9e5 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Fri, 21 Oct 2022 00:11:45 +0200 Subject: [PATCH 08/21] changes 1) pasing ID references 2) bugs in create_entities, where number of representations couldn't be updated 3) by_id node updated to current workflow ... other small fixes --- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 23 ++-- src/ifcsverchok/nodes/ifc/by_id.py | 21 ++-- src/ifcsverchok/nodes/ifc/create_entity.py | 119 +++++++++++++-------- 3 files changed, 97 insertions(+), 66 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 76736ad2f7..c0fae2e35b 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -88,7 +88,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" #no prop for now - self.outputs.new("SvVerticesSocket", "file") self.outputs.new("SvVerticesSocket", "Representations") self.width = 210 self.node_dict[hash(self)] = {} @@ -102,8 +101,8 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - print("#"*20, "\n running bmesh_to_ifc3 PROCESS()... \n", "#"*20,) - print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) + # print("#"*20, "\n running bmesh_to_ifc3 PROCESS()... \n", "#"*20,) + # print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) self.sv_input_names = [i.name for i in self.inputs] @@ -112,7 +111,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - print("node_dict: ", self.node_dict) + # print("node_dict: ", self.node_dict) if not self.inputs["blender_objects"].sv_get()[0]: return edit = False @@ -138,6 +137,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help # print("blender_objects: ", blender_objects) self.file = SvIfcStore.get_file() + print(self.file) self.context = self.get_context() if self.node_id not in SvIfcStore.id_map: @@ -147,23 +147,23 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.edit() representations = self.create(blender_objects) else: - representations = self.get_existing_element() + # representations = self.get_existing_element() + representations = SvIfcStore.id_map[self.node_id]["Representations"] print("representations: ", representations) print("SvIfcStore.id_map: ", SvIfcStore.id_map) self.outputs["Representations"].sv_set(representations) - self.outputs["file"].sv_set([[self.file]]) def create(self, blender_objects): - results = [] + representations_ids = [] for blender_object in blender_objects: representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.context) if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") - results.append([representation]) + representations_ids.append(representation.id()) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) - return results + return representations_ids def edit(self): # results = self.get_existing_element() @@ -171,15 +171,14 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help return for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: #if self.file.by_id(step_id).is_a('IfcShapeRepresentation'): - print("step_id: ", step_id) ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) del SvIfcStore.id_map[self.node_id]["Representations"] - return + return def get_existing_element(self): results = [] for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: - results.append([self.file.by_id(step_id)]) + results.append(self.file.by_id(step_id)) return results def get_context(self): diff --git a/src/ifcsverchok/nodes/ifc/by_id.py b/src/ifcsverchok/nodes/ifc/by_id.py index a2888e8475..1866f9dfac 100644 --- a/src/ifcsverchok/nodes/ifc/by_id.py +++ b/src/ifcsverchok/nodes/ifc/by_id.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore from bpy.props import StringProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode @@ -28,21 +29,21 @@ from sverchok.data_structure import updateNode class SvIfcById(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcById" bl_label = "IFC By Id" - file: StringProperty(name="file", update=updateNode) - id: StringProperty(name="id", update=updateNode) + id: StringProperty(name="Id(s)", update=updateNode) def sv_init(self, context): - self.inputs.new("SvStringsSocket", "file").prop_name = "file" self.inputs.new("SvStringsSocket", "id").prop_name = "id" - self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "Entities") + + def draw_buttons(self, context, layout): + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Get IFC element by step id. Takes one or multiple step ids." def process(self): - self.sv_input_names = ["file", "id"] - super().process() - - def process_ifc(self, file, id): - self.outputs["entity"].sv_set([[file.by_id(int(id))]]) - + self.ids = self.inputs["id"].sv_get() + print(self.ids) + self.file = SvIfcStore.get_file() + self.entities = [self.file.by_id(step_id) for step_id in self.ids] + self.outputs["Entities"].sv_set(self.entities) def register(): bpy.utils.register_class(SvIfcById) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 795503bc81..81ae8cc1b7 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -50,14 +50,24 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.outputs.new("SvStringsSocket", "file") # only for testing self.node_dict[hash(self)] = {} + def draw_buttons(self, context, layout): + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Create IFC Entity. Takes one or multiple inputs. \nIf 'Representation(s)' is given, that determines number of output entities. Otherwise, 'Names' is used." + + row = layout.row(align=True) + row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) + row.prop(self, 'refresh_local', icon='FILE_REFRESH') + + + + def process(self): print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - self.names = self.inputs["Names"].sv_get() - self.descriptions = self.inputs["Descriptions"].sv_get() + self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) + self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] - self.representations = self.inputs["Representations"].sv_get() + self.representations = flatten_data(self.inputs["Representations"].sv_get(), target_level=1) self.properties = self.inputs["Properties"].sv_get() @@ -84,78 +94,99 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper if self.refresh_local: edit = True + print("\nrepresentations before convert: ", self.representations) + + self.file = SvIfcStore.get_file() + if self.representations[0]: + self.representations = [self.file.by_id(step_id) for step_id in self.representations] + self.names = self.repeat_input_unique(self.names, len(self.representations)) + self.descriptions = self.repeat_input_unique(self.descriptions, len(self.representations)) + elif not self.representations[0]: + self.descriptions = self.repeat_input_unique(self.descriptions, len(self.names)) - self.names = repeat_last_for_length(self.names, len(self.representations), deepcopy=False) - self.descriptions = repeat_last_for_length(self.descriptions, len(self.representations), deepcopy=False) # print("REPRESENTATION: ", self.representations) # print("IfcClass: ",self.ifc_class) print("Names: ",self.names) print("Descriptions: ",self.descriptions) - - - - self.file = SvIfcStore.get_file() + # print("\nrepresentations after convert: ", self.representations) if self.node_id not in SvIfcStore.id_map: - enities = self.create() + entities = self.create() else: if edit is True: - enities = self.edit() + entities = self.edit() else: - enities = self.get_existing_element() + # entities = self.get_existing_element() + entities = SvIfcStore.id_map[self.node_id] - print("Entities: ", enities) + print("Entities: ", entities) print("SvIfcStore.id_map: ", SvIfcStore.id_map) - self.outputs["Entities"].sv_set(enities) + self.outputs["Entities"].sv_set(entities) self.outputs["file"].sv_set([[self.file]]) - def create(self): - # print("#"*20, "\n running create entity CREATE()... \n") - results = [] - for i, name in enumerate(self.names): - print(type(self.names[i][0])) + def create(self, index=None): + entities_ids = [] + iterator = range(len(self.names)) + if index is not None: + iterator = [index] + for i in iterator: try: - self.entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.ifc_class, name=self.names[i][0], description=self.descriptions[i][0]) + entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.ifc_class, name=self.names[i], description=self.descriptions[i]) try: - ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=self.representations[i][0]) + ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) except IndexError: pass - results.append([self.entity]) - SvIfcStore.id_map.setdefault(self.node_id, []).append(self.entity.id()) - except: - raise Exception("Something went wrong. Cannot create entity.") - return results + entities_ids.append(entity.id()) + SvIfcStore.id_map.setdefault(self.node_id, []).append(entity.id()) + except Exception as e: + raise Exception("Something went wrong. Cannot create entity.", e) + return entities_ids def edit(self): - results = [] + entities_ids = [] id_map_copy = SvIfcStore.id_map[self.node_id].copy() - for i, step_id in enumerate(id_map_copy): - self.entity = self.file.by_id(step_id) - self.entity.Name = self.names[i][0] - self.entity.Description = self.descriptions[i][0] + for i, _ in enumerate(self.names): + try: + step_id = id_map_copy[i] + except IndexError: + id = self.create(index=i) + entities_ids.append(id[0]) + continue + entity = self.file.by_id(step_id) + entity.Name = self.names[i] + entity.Description = self.descriptions[i] - if self.representations[i][0] and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): - ifcopenshell.api.run("geometry.assign_representation", self.file, product=self.entity, representation=self.representations[i][0]) - elif self.representations[i][0]: - self.entity.Representation = self.representations[i][0] - else: + try: + if self.representations[i] and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): + ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) + elif self.representations[i]: + entity.Representation = self.representations[i] + except IndexError: pass - if self.entity.is_a() != self.ifc_class: + if entity.is_a() != self.ifc_class: SvIfcStore.id_map[self.node_id].remove(step_id) - self.entity = ifcopenshell.util.schema.reassign_class(self.file, self.entity, self.ifc_class) - SvIfcStore.id_map.setdefault(self.node_id, []).append(self.entity.id()) - results.append([self.entity]) + entity = ifcopenshell.util.schema.reassign_class(self.file, entity, self.ifc_class) + SvIfcStore.id_map.setdefault(self.node_id, []).append(entity.id()) + entities_ids.append(entity.id()) + + if id_map_copy>entities_ids: + SvIfcStore.id_map[self.node_id] = entities_ids + return entities_ids + + def repeat_input_unique(self, input, count): + input = repeat_last_for_length(input, count, deepcopy=False) + if input[0]: + input = [a if not (s:=sum(j == a for j in input[:i])) else f'{a}-{s+1}' for i, a in enumerate(input)] # add number to duplicates + return input - return results def get_existing_element(self): - # print("#"*20, "\n running create entity get_existing_element()... \n", "#"*20,) results = [] for i, step_id in enumerate(SvIfcStore.id_map[self.node_id]): - self.entity = self.file.by_id(step_id) - results.append([self.entity]) + entity = self.file.by_id(step_id) + results.append([entity]) return results From 720de2ffe5253084b0c50fb8ad4bbbac191be94d Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Fri, 21 Oct 2022 17:16:24 +0200 Subject: [PATCH 09/21] updated by_type to current workflow + added sv_to_ifc --- src/ifcsverchok/__init__.py | 1 + src/ifcsverchok/nodes/ifc/by_id.py | 1 - src/ifcsverchok/nodes/ifc/by_type.py | 33 +++-- src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py | 136 +++++++++++++++++++ 4 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 92151487ec..9e72886eb1 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -69,6 +69,7 @@ def nodes_index(): ("ifc.api", "SvIfcApi"), ("ifc.api_WIP", "SvIfcApiWIP"), ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), + ("ifc.sverchok_to_ifc", "SvIfcSverchokToIfc"), ("ifc.create_project", "SvIfcCreateProject"), ("ifc.quick_project_setup", "SvIfcQuickProjectSetup") diff --git a/src/ifcsverchok/nodes/ifc/by_id.py b/src/ifcsverchok/nodes/ifc/by_id.py index 1866f9dfac..71dea45a5d 100644 --- a/src/ifcsverchok/nodes/ifc/by_id.py +++ b/src/ifcsverchok/nodes/ifc/by_id.py @@ -40,7 +40,6 @@ class SvIfcById(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCo def process(self): self.ids = self.inputs["id"].sv_get() - print(self.ids) self.file = SvIfcStore.get_file() self.entities = [self.file.by_id(step_id) for step_id in self.ids] self.outputs["Entities"].sv_set(self.entities) diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index c27be8426c..901f275e9f 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -21,13 +21,14 @@ import bpy import ifcopenshell import ifcsverchok.helper from bpy.props import StringProperty, EnumProperty +from ifcsverchok.ifcstore import SvIfcStore from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode def get_ifc_products(self, context): ifc_products = getattr(self, "ifc_products", []) - file = self.inputs["file"].sv_get()[0][0] + file = SvIfcStore.get_file() if not file: return [] if ifc_products and file: @@ -61,7 +62,7 @@ def get_ifc_classes(self, context): ifc_classes = getattr(self, "ifc_classes", []) if ifc_classes: return self.ifc_classes - file = self.inputs["file"].sv_get()[0][0] + file = SvIfcStore.get_file() if not file: return [] schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema) @@ -83,31 +84,35 @@ def get_ifc_classes(self, context): class SvIfcByType(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcByType" bl_label = "IFC By Type" - file: StringProperty(name="file", update=updateNode) - ifc_product: EnumProperty(items=get_ifc_products, name="Products", update=update_ifc_products) - ifc_class: EnumProperty(items=get_ifc_classes, name="Class", update=updateNode) - custom_ifc_class: StringProperty(name="Custom Ifc Class", update=updateNode) + ifc_product: EnumProperty(items=get_ifc_products, name="IfcProduct", description="Pick an IfcProduct from drop-down.", update=update_ifc_products) + ifc_class: EnumProperty(items=get_ifc_classes, name="IfcClass", description="Pick an IfcClass from drop-down.", update=updateNode) + custom_ifc_class: StringProperty(name="Custom IfcClass", description="Give the name of your custom IfcClass.", update=updateNode) def sv_init(self, context): - self.inputs.new("SvStringsSocket", "file").prop_name = "file" self.inputs.new("SvStringsSocket", "ifc_product").prop_name = "ifc_product" self.inputs.new("SvStringsSocket", "ifc_class").prop_name = "ifc_class" self.inputs.new("SvStringsSocket", "custom_ifc_class").prop_name = "custom_ifc_class" - self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "Entity") + self.width = 200 + + def draw_buttons(self, context, layout): + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Get IFC element(s) in file by type. \nPick an IfcProduct and an IfcClass or give a custom IfcClass." def process(self): - file = self.inputs["file"].sv_get()[0][0] - if file: + self.file = SvIfcStore.get_file() + if self.file: self.ifc_products = get_ifc_products(self, bpy.context) self.ifc_classes = get_ifc_classes(self, bpy.context) - self.sv_input_names = ["file", "ifc_product", "ifc_class", "custom_ifc_class"] + self.sv_input_names = ["ifc_product", "ifc_class", "custom_ifc_class"] super().process() - def process_ifc(self, file, ifc_product, ifc_class, custom_ifc_class): + def process_ifc(self, ifc_product, ifc_class, custom_ifc_class): if custom_ifc_class: - self.outputs["entity"].sv_set([file.by_type(custom_ifc_class)]) + self.outputs["Entity"].sv_set([self.file.by_type(custom_ifc_class)]) + elif ifc_class: + self.outputs["Entity"].sv_set([self.file.by_type(ifc_class)]) else: - self.outputs["entity"].sv_set([file.by_type(ifc_class)]) + self.outputs["Entity"].sv_set([]) def register(): diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py new file mode 100644 index 0000000000..6b4ca28816 --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -0,0 +1,136 @@ +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2022 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcsverchok.helper +import ifcopenshell.api +from ifcsverchok.ifcstore import SvIfcStore +import blenderbim.tool as tool +import blenderbim.core.geometry as core +from bpy.props import StringProperty, EnumProperty, IntProperty +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +class SvIfcSverchokToIfc(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcSverchokToIfc" + bl_label = "IFC Sverchok to IFC" + + context_types = [ + ('Model', 'Model', 'Context type: Model', 0), + ('Plan', 'Plan', 'Context type: Plan', 1), + ] + + context_identifiers = [ + ('Body', 'Body', 'Context identifier: Body', 0), + ('Annotation', 'Annotation', 'Context identifier: Annotation', 1), + ('Box', 'Box', 'Context identifier: Box', 2), + ('Axis', 'Axis', 'Context identifier: Axis', 3), + ] + target_views = [ + ('MODEL_VIEW', 'MODEL_VIEW', 'Target View: MODEL_VIEW', 0), + ('PLAN_VIEW', 'PLAN_VIEW', 'Target View: PLAN_VIEW', 1), + ('GRAPH_VIEW', 'GRAPH_VIEW', 'Target View: GRAPH_VIEW', 2), + ('SKETCH_VIEW', 'SKETCH_VIEW', 'Target View: SKETCH_VIEW', 3), + ] + + context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) + context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) + target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) + + def sv_init(self, context): + self.inputs.new("SvVerticesSocket", "Vertices") + self.inputs.new("SvStringsSocket", "Edges") + self.inputs.new("SvStringsSocket", "Faces") + self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" + self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" + self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" + + self.outputs.new("SvVerticesSocket", "Representation") + self.outputs.new("SvVerticesSocket", "File") + + def draw_buttons(self, context, layout): + op = layout.operator( + "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False + ).tooltip = "Blender mesh to Ifc Shape Representation" + + def process(self): + self.file = SvIfcStore.get_file() + + self.sv_input_names = [i.name for i in self.inputs] + + if self.node_id in SvIfcStore.id_map: + for step_id in SvIfcStore.id_map[self.node_id]: + ifcopenshell.api.run( + "geometry.remove_representation", self.file, representation=self.file.by_id(step_id) + ) + del SvIfcStore.id_map[self.node_id] + + results = [] + + representation = ifcopenshell.api.run( + "geometry.add_sverchok_representation", + self.file, + should_run_listeners=False, + context=self.get_context(), + vertices=self.inputs["Vertices"].sv_get(), + faces=self.inputs["Faces"].sv_get(), + ) + results.append(representation) + SvIfcStore.id_map.setdefault(self.node_id, []).append(representation.id()) + + SvIfcStore.file = self.file + + self.outputs["File"].sv_set([[self.file]]) # only for testing + self.outputs["Representation"].sv_set([results]) + + def get_context(self): + context = ifcopenshell.util.representation.get_context( + self.file, self.context_type, self.context_identifier, self.target_view + ) + if not context: + parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) + if not parent: + parent = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) + context = ifcopenshell.api.run( + "context.add_context", + self.file, + context_type=self.context_type, + context_identifier=self.context_identifier, + target_view=self.target_view, + parent=model, + ) + return context + + def sv_free(self): + print("it was deleted") + try: + pass + # SvIfcStore.id_map.pop(self.representation.id()) + # SvIfcStore.id_map.pop(self.context.id()) + except KeyError or AttributeError: + pass + + +def register(): + bpy.utils.register_class(SvIfcSverchokToIfc) + + +def unregister(): + bpy.utils.unregister_class(SvIfcSverchokToIfc) \ No newline at end of file From cbe3fd42a70840c31d785fc3a1bac4d0a5781072 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Sun, 23 Oct 2022 16:18:42 +0200 Subject: [PATCH 10/21] sverchok_to_ifc node added + works for multiple geometries. Parent contexts also get deleted if not used. --- src/ifcsverchok/__init__.py | 4 +- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 44 ++---- src/ifcsverchok/nodes/ifc/create_entity.py | 2 - src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py | 145 ++++++++++++++----- 4 files changed, 124 insertions(+), 71 deletions(-) diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 9e72886eb1..29c84a109f 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -68,8 +68,8 @@ def nodes_index(): ("ifc.select_blender_objects", "SvIfcSelectBlenderObjects"), ("ifc.api", "SvIfcApi"), ("ifc.api_WIP", "SvIfcApiWIP"), - ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcGeo"), - ("ifc.sverchok_to_ifc", "SvIfcSverchokToIfc"), + ("ifc.bmesh_to_ifc", "SvIfcBMeshToIfcRepr"), + ("ifc.sverchok_to_ifc", "SvIfcSverchokToIfcRepr"), ("ifc.create_project", "SvIfcCreateProject"), ("ifc.quick_project_setup", "SvIfcQuickProjectSetup") diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index c0fae2e35b..6c7e5260a5 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -17,6 +17,7 @@ # along with IfcSverchok. If not, see . from copy import deepcopy +from decimal import Context from email.policy import default import bpy import ifcopenshell @@ -89,21 +90,17 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" #no prop for now self.outputs.new("SvVerticesSocket", "Representations") - self.width = 210 - self.node_dict[hash(self)] = {} + def draw_buttons(self, context, layout): - layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation" + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation. \nTakes one or multiple geometries." row = layout.row(align=True) row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) row.prop(self, 'refresh_local', icon='FILE_REFRESH') - def process(self): - # print("#"*20, "\n running bmesh_to_ifc3 PROCESS()... \n", "#"*20,) - # print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - + def process(self): self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: @@ -111,35 +108,24 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - # print("node_dict: ", self.node_dict) if not self.inputs["blender_objects"].sv_get()[0]: return edit = False for i in range(len(self.inputs)): input = self.inputs[i].sv_get(deepcopy=False) - # print("input: ", input) - # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True self.node_dict[hash(self)][self.inputs[i].name] = input + blender_objects = self.inputs["blender_objects"].sv_get() + self.file = SvIfcStore.get_file() + #temporary if self.paradigm == "Extrusion": raise Exception("Extrusion not yet implemented.") return - if self.refresh_local: edit = True - - blender_objects = self.inputs["blender_objects"].sv_get() - # print("\ncontext_type: ", self.context_type) - # print("context_identifier: ", self.context_identifier) - # print("blender_objects: ", blender_objects) - - self.file = SvIfcStore.get_file() - print(self.file) - - self.context = self.get_context() if self.node_id not in SvIfcStore.id_map: representations = self.create(blender_objects) else: @@ -151,14 +137,13 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help representations = SvIfcStore.id_map[self.node_id]["Representations"] print("representations: ", representations) - print("SvIfcStore.id_map: ", SvIfcStore.id_map) self.outputs["Representations"].sv_set(representations) def create(self, blender_objects): representations_ids = [] for blender_object in blender_objects: - representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.context) + representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.get_context()) if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids.append(representation.id()) @@ -203,19 +188,22 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help return context def sv_free(self): - try: - print('DELETING') self.file = SvIfcStore.get_file() if "Representations" in SvIfcStore.id_map[self.node_id]: for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: - print("step_id: ", step_id) ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) if "Contexts" in SvIfcStore.id_map[self.node_id]: for context_id in SvIfcStore.id_map[self.node_id]["Contexts"]: - if not self.file.get_inverse(self.file.by_id(self.context.id())): - ifcopenshell.api.run("context.remove_context", self.file, representation=self.file.by_id(context_id)) + context = self.file.by_id(context_id) + if not self.file.get_inverse(context): + if self.file.by_id(context_id).ParentContext: + parent = self.file.by_id(context_id).ParentContext + ifcopenshell.api.run("context.remove_context", self.file, context=context) + if parent: + if not self.file.get_inverse(parent): + ifcopenshell.api.run("context.remove_context", self.file, context=parent) print("Removed context with step ID: ", context_id) SvIfcStore.id_map[self.node_id]["Contexts"].remove(context_id) del SvIfcStore.id_map[self.node_id] diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 81ae8cc1b7..bce4f88c01 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -191,9 +191,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper def sv_free(self): - try: - print('DELETING') del SvIfcStore.id_map[self.node_id] del self.node_dict[hash(self)] print('Node was deleted') diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index 6b4ca28816..96acca45bb 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with IfcSverchok. If not, see . +from copy import deepcopy import bpy import ifcopenshell import ifcsverchok.helper @@ -23,15 +24,21 @@ import ifcopenshell.api from ifcsverchok.ifcstore import SvIfcStore import blenderbim.tool as tool import blenderbim.core.geometry as core -from bpy.props import StringProperty, EnumProperty, IntProperty +from bpy.props import StringProperty, EnumProperty, IntProperty, FloatVectorProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode -class SvIfcSverchokToIfc(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): - bl_idname = "SvIfcSverchokToIfc" - bl_label = "IFC Sverchok to IFC" +class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + """ + Triggers: Sv to Ifc Repr + Tooltip: Sverchok geometry to Ifc Shape Representation + """ + bl_idname = "SvIfcSverchokToIfcRepr" + bl_label = "IFC Sverchok to IFC Repr" + node_dict = {} + n_id: StringProperty() context_types = [ ('Model', 'Model', 'Context type: Model', 0), ('Plan', 'Plan', 'Context type: Plan', 1), @@ -53,52 +60,94 @@ class SvIfcSverchokToIfc(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) - + def sv_init(self, context): - self.inputs.new("SvVerticesSocket", "Vertices") - self.inputs.new("SvStringsSocket", "Edges") - self.inputs.new("SvStringsSocket", "Faces") self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" - - self.outputs.new("SvVerticesSocket", "Representation") + self.inputs.new("SvVerticesSocket", "Vertices") + self.inputs.new("SvStringsSocket", "Edges") + self.inputs.new("SvStringsSocket", "Faces") + self.outputs.new("SvVerticesSocket", "Representation(s)") self.outputs.new("SvVerticesSocket", "File") + self.width = 210 + self.node_dict[hash(self)] = {} def draw_buttons(self, context, layout): op = layout.operator( "node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False - ).tooltip = "Blender mesh to Ifc Shape Representation" + ).tooltip = "Sverchok geometry to Ifc Shape Representation. \nTakes one or multiple geometries." def process(self): + if not any(socket.is_linked for socket in self.inputs): + return + self.file = SvIfcStore.get_file() - self.sv_input_names = [i.name for i in self.inputs] - if self.node_id in SvIfcStore.id_map: - for step_id in SvIfcStore.id_map[self.node_id]: - ifcopenshell.api.run( - "geometry.remove_representation", self.file, representation=self.file.by_id(step_id) - ) - del SvIfcStore.id_map[self.node_id] + if hash(self) not in self.node_dict: + self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict[hash(self)]: + self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + + print("node_dict: ", self.node_dict) + edit = False + for i in range(len(self.inputs)): + input = self.inputs[i].sv_get(deepcopy=False) + if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: + edit = True + print("Edit = True") + self.node_dict[hash(self)][self.inputs[i].name] = input + + self.vertices = self.inputs["Vertices"].sv_get(deepcopy=False) + self.edges = self.inputs["Edges"].sv_get(deepcopy=False) + self.faces = self.inputs["Faces"].sv_get(deepcopy=False) + data = list(zip(self.vertices, self.edges, self.faces)) + + if self.node_id not in SvIfcStore.id_map: + + representations = self.create(data) + else: + print("edit: ", edit) + if edit is True: + self.edit() + representations = self.create(data) + else: + # representations = self.get_existing_element() + representations = SvIfcStore.id_map[self.node_id]["Representations"] - results = [] - - representation = ifcopenshell.api.run( + self.outputs["Representation(s)"].sv_set(representations) + + def create(self, data): + representations_ids = [] + self.context = self.get_context() + for item in data: + representation = ifcopenshell.api.run( "geometry.add_sverchok_representation", self.file, should_run_listeners=False, - context=self.get_context(), - vertices=self.inputs["Vertices"].sv_get(), - faces=self.inputs["Faces"].sv_get(), - ) - results.append(representation) - SvIfcStore.id_map.setdefault(self.node_id, []).append(representation.id()) - - SvIfcStore.file = self.file - - self.outputs["File"].sv_set([[self.file]]) # only for testing - self.outputs["Representation"].sv_set([results]) + context=self.context, + vertices=[item[0]], + edges=[item[1]], + faces=[item[2]], + ) + if not representation: + raise Exception("Couldn't create representation. Possibly wrong context.") + representations_ids.append(representation.id()) + print("Representation: ", representation) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) + return representations_ids + + def edit(self): + # results = self.get_existing_element() + if "Representations" not in SvIfcStore.id_map[self.node_id]: + return + for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: + ifcopenshell.api.run( + "geometry.remove_representation", self.file, representation=self.file.by_id(step_id) + ) + del SvIfcStore.id_map[self.node_id]["Representations"] + return def get_context(self): context = ifcopenshell.util.representation.get_context( @@ -114,23 +163,41 @@ class SvIfcSverchokToIfc(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helpe context_type=self.context_type, context_identifier=self.context_identifier, target_view=self.target_view, - parent=model, + parent=parent, ) + print("context: ", context) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) return context def sv_free(self): - print("it was deleted") try: - pass - # SvIfcStore.id_map.pop(self.representation.id()) - # SvIfcStore.id_map.pop(self.context.id()) + self.file = SvIfcStore.get_file() + if "Representations" in SvIfcStore.id_map[self.node_id]: + for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: + ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) + + if "Contexts" in SvIfcStore.id_map[self.node_id]: + for context_id in SvIfcStore.id_map[self.node_id]["Contexts"]: + context = self.file.by_id(context_id) + if not self.file.get_inverse(context): + if self.file.by_id(context_id).ParentContext: + parent = self.file.by_id(context_id).ParentContext + ifcopenshell.api.run("context.remove_context", self.file, context=context) + if parent: + if not self.file.get_inverse(parent): + ifcopenshell.api.run("context.remove_context", self.file, context=parent) + print("Removed context with step ID: ", context_id) + SvIfcStore.id_map[self.node_id]["Contexts"].remove(context_id) + del SvIfcStore.id_map[self.node_id] + del self.node_dict[hash(self)] + print('Node was deleted') except KeyError or AttributeError: pass def register(): - bpy.utils.register_class(SvIfcSverchokToIfc) + bpy.utils.register_class(SvIfcSverchokToIfcRepr) def unregister(): - bpy.utils.unregister_class(SvIfcSverchokToIfc) \ No newline at end of file + bpy.utils.unregister_class(SvIfcSverchokToIfcRepr) \ No newline at end of file From 952a0ac2a4385269130e2bc0d76f15133387c02c Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Sun, 23 Oct 2022 20:25:36 +0200 Subject: [PATCH 11/21] create_shape node updated + minor changes --- src/ifcsverchok/nodes/ifc/by_id.py | 11 +- src/ifcsverchok/nodes/ifc/create_shape.py | 117 ++++++++++++------- src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py | 11 +- 3 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/by_id.py b/src/ifcsverchok/nodes/ifc/by_id.py index 71dea45a5d..c67ac956a9 100644 --- a/src/ifcsverchok/nodes/ifc/by_id.py +++ b/src/ifcsverchok/nodes/ifc/by_id.py @@ -23,13 +23,13 @@ import ifcsverchok.helper from ifcsverchok.ifcstore import SvIfcStore from bpy.props import StringProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import updateNode, flatten_data class SvIfcById(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcById" bl_label = "IFC By Id" - id: StringProperty(name="Id(s)", update=updateNode) + id: StringProperty(name="Id(s)", update=updateNode, ) def sv_init(self, context): self.inputs.new("SvStringsSocket", "id").prop_name = "id" @@ -39,9 +39,12 @@ class SvIfcById(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCo layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Get IFC element by step id. Takes one or multiple step ids." def process(self): - self.ids = self.inputs["id"].sv_get() + self.ids = flatten_data(self.inputs["id"].sv_get(), target_level=1) + print(self.ids) + if not self.ids[0]: + return self.file = SvIfcStore.get_file() - self.entities = [self.file.by_id(step_id) for step_id in self.ids] + self.entities = [self.file.by_id(int(step_id)) for step_id in self.ids] self.outputs["Entities"].sv_set(self.entities) def register(): diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index 2e485b1fb6..2700e3b13a 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -21,67 +21,104 @@ import bpy import logging import ifcopenshell import ifcsverchok.helper +from ifcsverchok.ifcstore import SvIfcStore import blenderbim.bim.import_ifc -from bpy.props import StringProperty +from bpy.props import StringProperty, PointerProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode - -from sverchok.data_structure import zip_long_repeat +from sverchok.data_structure import updateNode, flatten_data -class SvIfcCreateShapeRefresh(bpy.types.Operator): - bl_idname = "node.sv_ifc_create_shape_refresh" - bl_label = "IFC Create Shape Refresh" - bl_options = {"UNDO"} +# class SvIfcCreateShapeRefresh(bpy.types.Operator): +# bl_idname = "node.sv_ifc_create_shape_refresh" +# bl_label = "IFC Create Shape Refresh" +# bl_options = {"UNDO"} - tree_name: StringProperty(default="") - node_name: StringProperty(default="") - def execute(self, context): - node = bpy.data.node_groups[self.tree_name].nodes[self.node_name] - node.process() - return {"FINISHED"} +# tree_name: StringProperty(default="") +# node_name: StringProperty(default="") + +# def execute(self, context): +# node = bpy.data.node_groups[self.tree_name].nodes[self.node_name] +# node.process() +# return {"FINISHED"} class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + """ + Triggers: Ifc create shape by entity + Tooltip: Create Blender shape by Ifc Entity + """ + is_scene_dependent = True + is_interactive = False + node_dict = {} + def refresh_node(self, context): + if self.refresh_local: + self.process() + self.refresh_local = False + + refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) + bl_idname = "SvIfcCreateShape" - bl_label = "IFC Create Shape" - file: StringProperty(name="file", update=updateNode) - entity: StringProperty(name="entity", update=updateNode) + bl_label = "IFC Create Blender Shape" + entity: StringProperty(name="Entities", update=updateNode) + def sv_init(self, context): - self.inputs.new("SvStringsSocket", "file").prop_name = "file" - self.inputs.new("SvStringsSocket", "entity").prop_name = "entity" + self.inputs.new("SvStringsSocket", "Entities").prop_name = "entity" + self.outputs.new('SvStringsSocket', "Object(s)") def draw_buttons(self, context, layout): - self.wrapper_tracked_ui_draw_op(layout, "node.sv_ifc_create_shape_refresh", icon="FILE_REFRESH", text="Refresh") + # self.wrapper_tracked_ui_draw_op(layout, "node.sv_ifc_create_shape_refresh", icon="FILE_REFRESH", text="Refresh") + row = layout.row(align=True) + row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Create Blender shape from Ifc Entity. Takes one or multiple Ifc Entities." + # row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) + row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - self.sv_input_names = ["file", "entity"] - super().process() - - def process_ifc(self, file, entity): - try: - if not entity.is_a("IfcProduct"): - return - logger = logging.getLogger("ImportIFC") - self.ifc_import_settings = blenderbim.bim.import_ifc.IfcImportSettings.factory(bpy.context, "", logger) - settings = ifcopenshell.geom.settings() - shape = ifcopenshell.geom.create_shape(settings, entity) - ifc_importer = blenderbim.bim.import_ifc.IfcImporter(self.ifc_import_settings) - ifc_importer.file = file - mesh = ifc_importer.create_mesh(entity, shape) - obj = bpy.data.objects.new("IFC Element", mesh) - bpy.context.scene.collection.objects.link(obj) - except: - raise Exception("Entity could not be converted into a shape. Entity: {}".format(entity)) + print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) + print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) + print("node_dict: ", self.node_dict) + self.entities = flatten_data(self.inputs["Entities"].sv_get(), target_level = 1) + if not self.entities[0]: + return + + if self.refresh_local or hash(self) not in self.node_dict: + print("grr") + self.file = SvIfcStore.get_file() + blender_objects = self.create() + self.node_dict[hash(self)] = blender_objects + print("blender_objects: ", blender_objects) + else: + blender_objects = self.node_dict[hash(self)] + + self.outputs["Object(s)"].sv_set(blender_objects) + def create(self): + blender_objects = [] + for entity in self.entities: + print("entity: ", entity) + try: + if not entity.is_a("IfcProduct"): + return + logger = logging.getLogger("ImportIFC") + self.ifc_import_settings = blenderbim.bim.import_ifc.IfcImportSettings.factory(bpy.context, "", logger) + settings = ifcopenshell.geom.settings() + shape = ifcopenshell.geom.create_shape(settings, entity) + ifc_importer = blenderbim.bim.import_ifc.IfcImporter(self.ifc_import_settings) + ifc_importer.file = self.file + mesh = ifc_importer.create_mesh(entity, shape) + obj = bpy.data.objects.new("IFC Element", mesh) + blender_objects.append(obj) + bpy.context.scene.collection.objects.link(obj) + except: + raise Exception("Entity could not be converted into a shape. Entity: {}".format(entity)) + return blender_objects def register(): - bpy.utils.register_class(SvIfcCreateShapeRefresh) + # bpy.utils.register_class(SvIfcCreateShapeRefresh) bpy.utils.register_class(SvIfcCreateShape) def unregister(): bpy.utils.unregister_class(SvIfcCreateShape) - bpy.utils.unregister_class(SvIfcCreateShapeRefresh) + # bpy.utils.unregister_class(SvIfcCreateShapeRefresh) diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index 96acca45bb..c95afbe148 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -69,7 +69,6 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h self.inputs.new("SvStringsSocket", "Edges") self.inputs.new("SvStringsSocket", "Faces") self.outputs.new("SvVerticesSocket", "Representation(s)") - self.outputs.new("SvVerticesSocket", "File") self.width = 210 self.node_dict[hash(self)] = {} @@ -102,26 +101,26 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h self.vertices = self.inputs["Vertices"].sv_get(deepcopy=False) self.edges = self.inputs["Edges"].sv_get(deepcopy=False) self.faces = self.inputs["Faces"].sv_get(deepcopy=False) - data = list(zip(self.vertices, self.edges, self.faces)) + geo_data = list(zip(self.vertices, self.edges, self.faces)) if self.node_id not in SvIfcStore.id_map: - representations = self.create(data) + representations = self.create(geo_data) else: print("edit: ", edit) if edit is True: self.edit() - representations = self.create(data) + representations = self.create(geo_data) else: # representations = self.get_existing_element() representations = SvIfcStore.id_map[self.node_id]["Representations"] self.outputs["Representation(s)"].sv_set(representations) - def create(self, data): + def create(self, geo_data): representations_ids = [] self.context = self.get_context() - for item in data: + for item in geo_data: representation = ifcopenshell.api.run( "geometry.add_sverchok_representation", self.file, From 567de9a3ba2acec049a6dc8ad4027070ff2dc2c0 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Sun, 23 Oct 2022 21:51:26 +0200 Subject: [PATCH 12/21] write_file node updated --- src/ifcsverchok/nodes/ifc/create_shape.py | 10 +---- src/ifcsverchok/nodes/ifc/write_file.py | 45 ++++++++++++++++++----- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index 2700e3b13a..8db13b6f61 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -56,7 +56,7 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. self.process() self.refresh_local = False - refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) + refresh_local: BoolProperty(name="Create shape(s)", description="Update Node", update=refresh_node) bl_idname = "SvIfcCreateShape" bl_label = "IFC Create Blender Shape" @@ -68,26 +68,19 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. self.outputs.new('SvStringsSocket', "Object(s)") def draw_buttons(self, context, layout): - # self.wrapper_tracked_ui_draw_op(layout, "node.sv_ifc_create_shape_refresh", icon="FILE_REFRESH", text="Refresh") row = layout.row(align=True) row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Create Blender shape from Ifc Entity. Takes one or multiple Ifc Entities." - # row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) - print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - print("node_dict: ", self.node_dict) self.entities = flatten_data(self.inputs["Entities"].sv_get(), target_level = 1) if not self.entities[0]: return if self.refresh_local or hash(self) not in self.node_dict: - print("grr") self.file = SvIfcStore.get_file() blender_objects = self.create() self.node_dict[hash(self)] = blender_objects - print("blender_objects: ", blender_objects) else: blender_objects = self.node_dict[hash(self)] @@ -96,7 +89,6 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. def create(self): blender_objects = [] for entity in self.entities: - print("entity: ", entity) try: if not entity.is_a("IfcProduct"): return diff --git a/src/ifcsverchok/nodes/ifc/write_file.py b/src/ifcsverchok/nodes/ifc/write_file.py index 59df9fc84f..1092e6ebb2 100644 --- a/src/ifcsverchok/nodes/ifc/write_file.py +++ b/src/ifcsverchok/nodes/ifc/write_file.py @@ -17,30 +17,55 @@ # You should have received a copy of the GNU General Public License # along with IfcSverchok. If not, see . +from os.path import abspath, splitext import bpy import ifcopenshell import ifcsverchok.helper -from bpy.props import StringProperty +from ifcsverchok.ifcstore import SvIfcStore +from bpy.props import StringProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import updateNode, flatten_data class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + """ + Triggers: Ifc write to file + Tooltip: Write active Sverchok Ifc file to path + """ + def refresh_node_local(self, context): + if self.refresh_local: + self.process() + self.refresh_local = False + + # out = "" + refresh_local: BoolProperty(name="Write", description="Write to file", update=refresh_node_local) + bl_idname = "SvIfcWriteFile" bl_label = "IFC Write File" - file: StringProperty(name="file", update=updateNode) - path: StringProperty(name="path", update=updateNode) + path: StringProperty(name="path", description="File path to write to. Can be relative.", update=updateNode) def sv_init(self, context): - self.inputs.new("SvStringsSocket", "file").prop_name = "file" self.inputs.new("SvStringsSocket", "path").prop_name = "path" + self.outputs.new("SvStringsSocket", "output") + + def draw_buttons(self, context, layout): + row = layout.row(align=True) + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Writes active Ifc file to path.\n It will overwrite an existing file." + row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - self.sv_input_names = ["file", "path"] - super().process() - - def process_ifc(self, file, path): - file.write(path) + path = flatten_data(self.inputs["path"].sv_get(), target_level = 1)[0] + if not path: + return + path = abspath(path) + file = SvIfcStore.get_file() + _, ext = splitext(path) + if not ext: + raise Exception("Bad path. Provide a path to a file.") + if self.refresh_local and ext: + file.write(path) + self.outputs["output"].sv_set(f"File written successfully to: {path}.") + def register(): From fb18bd411841511389fedd15bfb7852eb93b6f82 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 24 Oct 2022 00:08:59 +0200 Subject: [PATCH 13/21] added entity locations --- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 22 ++++++++++++++++----- src/ifcsverchok/nodes/ifc/create_entity.py | 23 ++++++++++++++++------ src/ifcsverchok/nodes/ifc/write_file.py | 2 +- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 6c7e5260a5..344170d18d 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -54,6 +54,9 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) n_id: StringProperty() + flat_output: BoolProperty( + name="Flat output", description="Flatten output by list-joining level 1", + default=True, update=updateNode) context_types = [ ('Model', 'Model', 'Context type: Model', 0), ('Plan', 'Plan', 'Context type: Plan', 1), @@ -90,9 +93,8 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" #no prop for now self.outputs.new("SvVerticesSocket", "Representations") + self.outputs.new("SvMatrixSocket", "Locations") - - def draw_buttons(self, context, layout): layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Blender mesh to Ifc Shape Representation. \nTakes one or multiple geometries." @@ -127,28 +129,37 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help if self.refresh_local: edit = True if self.node_id not in SvIfcStore.id_map: - representations = self.create(blender_objects) + representations, locations = self.create(blender_objects) else: if edit is True: self.edit() - representations = self.create(blender_objects) + representations, locations = self.create(blender_objects) else: # representations = self.get_existing_element() representations = SvIfcStore.id_map[self.node_id]["Representations"] + locations = SvIfcStore.id_map[self.node_id]["Locations"] print("representations: ", representations) + print("locations: ", locations) self.outputs["Representations"].sv_set(representations) + self.outputs["Locations"].sv_set(locations) def create(self, blender_objects): representations_ids = [] + locations = [] + add_matrix = locations.extend if self.flat_output else locations.append for blender_object in blender_objects: representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.get_context()) if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids.append(representation.id()) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) - return representations_ids + location = blender_object.matrix_world + print("\n", "#"*30, "location: ", location) + add_matrix(location) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(location) + return representations_ids, locations def edit(self): # results = self.get_existing_element() @@ -158,6 +169,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help #if self.file.by_id(step_id).is_a('IfcShapeRepresentation'): ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) del SvIfcStore.id_map[self.node_id]["Representations"] + del SvIfcStore.id_map[self.node_id]["Locations"] return def get_existing_element(self): diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index bce4f88c01..36efae5d41 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -13,7 +13,7 @@ from ifcsverchok.ifcstore import SvIfcStore import bpy import ifcopenshell -from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty, PointerProperty +from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_length @@ -38,6 +38,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper Descriptions: StringProperty(name="Descriptions", default="", update=updateNode) IfcClass: StringProperty(name="IfcClass", update=updateNode) Representations: StringProperty(name="Representations", default="", update=updateNode) + # Locations: FloatVectorProperty(name="Locations", default="", update=updateNode) Properties: StringProperty(name="properties", update=updateNode) def sv_init(self, context): @@ -45,6 +46,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.inputs.new("SvStringsSocket", "Descriptions").prop_name = "Descriptions" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" self.inputs.new("SvStringsSocket", "Representations").prop_name = "Representations" + self.inputs.new("SvMatrixSocket", "Locations").is_mandatory=False self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" self.outputs.new("SvStringsSocket", "Entities") self.outputs.new("SvStringsSocket", "file") # only for testing @@ -57,9 +59,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) row.prop(self, 'refresh_local', icon='FILE_REFRESH') - - - def process(self): print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) @@ -68,6 +67,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] self.representations = flatten_data(self.inputs["Representations"].sv_get(), target_level=1) + self.locations = flatten_data(self.inputs["Locations"].sv_get(default=[]), target_level=1) self.properties = self.inputs["Properties"].sv_get() @@ -84,7 +84,9 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper edit = False for i in range(len(self.inputs)): - input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False) + # if self.sv_input_names[i] == "Locations": + # input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False, default = []) + input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False, default =[]) # print("input: ", input) # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: @@ -137,6 +139,11 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) except IndexError: pass + try: + print("LOCATION[i]: ", self.locations[i]) + ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) + except IndexError: + pass entities_ids.append(entity.id()) SvIfcStore.id_map.setdefault(self.node_id, []).append(entity.id()) except Exception as e: @@ -164,7 +171,11 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper entity.Representation = self.representations[i] except IndexError: pass - + try: + print("LOCATION[i]: ", self.locations[i]) + ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) + except IndexError: + pass if entity.is_a() != self.ifc_class: SvIfcStore.id_map[self.node_id].remove(step_id) entity = ifcopenshell.util.schema.reassign_class(self.file, entity, self.ifc_class) diff --git a/src/ifcsverchok/nodes/ifc/write_file.py b/src/ifcsverchok/nodes/ifc/write_file.py index 1092e6ebb2..e2f7c51819 100644 --- a/src/ifcsverchok/nodes/ifc/write_file.py +++ b/src/ifcsverchok/nodes/ifc/write_file.py @@ -50,7 +50,7 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv def draw_buttons(self, context, layout): row = layout.row(align=True) - layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Writes active Ifc file to path.\n It will overwrite an existing file." + row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Writes active Ifc file to path.\n It will overwrite an existing file." row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): From d460a890a74bb83f384ce7c98579146fd7af3c21 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 24 Oct 2022 01:45:00 +0200 Subject: [PATCH 14/21] Add_spacial_element node updated to work with multiple elements. V0.1 - still a bit buggy. --- .../nodes/ifc/add_spatial_element.py | 96 ++++++++++++------- src/ifcsverchok/nodes/ifc/create_entity.py | 14 +-- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index 1f79bf4ed1..fcf196c6ab 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -10,65 +10,91 @@ import ifcopenshell from bpy.props import StringProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_length, ensure_min_nesting class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcAddSpatialElement" bl_label = "IFC Add Spatial Element" - Name: StringProperty(name="Name", update=updateNode) + Name: StringProperty(name="Name(s)", update=updateNode) IfcClass: StringProperty(name="IFC Class", update=updateNode, default="IfcSpace") Elements: StringProperty(name="Elements", update=updateNode) + len_elements = 0 def sv_init(self, context): - self.inputs.new("SvStringsSocket", "Name").prop_name = "Name" + self.inputs.new("SvStringsSocket", "Name(s)").prop_name = "Name" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" - self.outputs.new("SvStringsSocket", "entity") + self.outputs.new("SvStringsSocket", "Entities") self.outputs.new("SvStringsSocket", "file") def process(self): if not any(socket.is_linked for socket in self.outputs): return - name = self.inputs["Name"].sv_get()[0][0] - ifc_class = self.inputs["IfcClass"].sv_get()[0][0] - elements = self.inputs["Elements"].sv_get()[0] - - if SvIfcStore.file is None: - SvIfcStore.file = SvIfcStore.create_boilerplate() + self.names = flatten_data(self.inputs["Name(s)"].sv_get(), target_level=1) + self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] + self.elements = ensure_min_nesting(self.inputs["Elements"].sv_get(), 2) + self.elements = flatten_data(self.elements, target_level=2) + print("elements: ", self.elements) self.file = SvIfcStore.get_file() + self.elements = [[self.file.by_id(step_id) for step_id in element] for element in self.elements] + + print("len elements: ", len(self.elements)) + print("elements: ", self.elements) + self.names = self.repeat_input_unique(self.names, len(self.elements)) + print("Names: ",self.names) - if self.node_id not in SvIfcStore.id_map.values(): - element = self.create(name, ifc_class, elements) + if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.len_elements): + print("\nRunning create") + elements = self.create() + self.len_elements = len(self.elements) else: - element = self.edit(name, ifc_class, elements) + elements = self.edit() + print("\n ##### results: ", elements) + self.outputs["Entities"].sv_set(elements) + self.outputs["file"].sv_set([self.file]) - self.outputs["entity"].sv_set([[element]]) - self.outputs["file"].sv_set([[self.file]]) - - def create(self, name, ifc_class, elements): + def create(self): results = [] - result = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class) - for element in elements: - ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=result) - SvIfcStore.id_map[result.id()] = self.node_id + for i, element in enumerate(self.elements): + print("element: ", element) + result = ifcopenshell.api.run("root.create_entity", self.file, name=self.names[i], ifc_class=self.ifc_class) + for items in element: + print("items: ", items) + ifcopenshell.api.run("spatial.assign_container", self.file, product=items, relating_structure=result) + SvIfcStore.id_map[result.id()] = self.node_id + SvIfcStore.id_map.setdefault(self.node_id, []).append(result.id()) results.append(result) - return result + return results - def edit(self, name, ifc_class, elements): - result = self.get_existing_element() - subelements = set(ifcopenshell.util.element.get_decomposition(result)) - elements_set = set(elements) - print("RESULT: ", result) - print("subelements: ", subelements) - print("elements_set: ", elements_set) - for removed_element in subelements - elements_set: - # Just realised I don't have a spatial.unassign_container, but if so we'd do it here - pass - for added_element in elements_set - subelements: - ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) - return result + def edit(self): + results = [] + results_ids = SvIfcStore.id_map[self.node_id] + for result_id in results_ids: + result = self.file.by_id(result_id) + print("\n\nresult: ", result) + subelements = set(ifcopenshell.util.element.get_decomposition(result)) + for element in self.elements: + print("\nElement: ", element) + element_set = set(element) + print("\nRESULT: ", result) + print("subelements: ", subelements) + print("elements_set: ", element_set) + for removed_element in subelements - element_set: + # Just realised I don't have a spatial.unassign_container, but if so we'd do it here + pass + for added_element in element_set - subelements: + ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) + print("assigned container") + results.append(result) + return results + + def repeat_input_unique(self, input, count): + input = repeat_last_for_length(input, count, deepcopy=False) + if input[0]: + input = [a if not (s:=sum(j == a for j in input[:i])) else f'{a}-{s+1}' for i, a in enumerate(input)] # add number to duplicates + return input def get_existing_element(self): entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 36efae5d41..4ae62b1394 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -100,7 +100,10 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.file = SvIfcStore.get_file() if self.representations[0]: - self.representations = [self.file.by_id(step_id) for step_id in self.representations] + try: + self.representations = [self.file.by_id(step_id) for step_id in self.representations] + except Exception as e: + raise self.names = self.repeat_input_unique(self.names, len(self.representations)) self.descriptions = self.repeat_input_unique(self.descriptions, len(self.representations)) elif not self.representations[0]: @@ -191,15 +194,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper if input[0]: input = [a if not (s:=sum(j == a for j in input[:i])) else f'{a}-{s+1}' for i, a in enumerate(input)] # add number to duplicates return input - - - def get_existing_element(self): - results = [] - for i, step_id in enumerate(SvIfcStore.id_map[self.node_id]): - entity = self.file.by_id(step_id) - results.append([entity]) - return results - def sv_free(self): try: From a592736b222f247d814d5258d4ced9ba3410b8ed Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 24 Oct 2022 14:06:23 +0200 Subject: [PATCH 15/21] Add_spatial_element node updated --- src/ifcsverchok/nodes/ifc/add_spatial_element.py | 15 ++++++++++----- src/ifcsverchok/nodes/ifc/create_shape.py | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index fcf196c6ab..24d1aa6f02 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -62,10 +62,13 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h result = ifcopenshell.api.run("root.create_entity", self.file, name=self.names[i], ifc_class=self.ifc_class) for items in element: print("items: ", items) - ifcopenshell.api.run("spatial.assign_container", self.file, product=items, relating_structure=result) + if items.is_a("IfcSpatialElement") or items.is_a("IfcSpatialStructureElement"): + ifcopenshell.api.run("aggregate.assign_object", self.file, product=items, relating_object=result) + else: + ifcopenshell.api.run("spatial.assign_container", self.file, product=items, relating_structure=result) SvIfcStore.id_map[result.id()] = self.node_id SvIfcStore.id_map.setdefault(self.node_id, []).append(result.id()) - results.append(result) + results.append(result.id()) return results def edit(self): @@ -73,7 +76,6 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h results_ids = SvIfcStore.id_map[self.node_id] for result_id in results_ids: result = self.file.by_id(result_id) - print("\n\nresult: ", result) subelements = set(ifcopenshell.util.element.get_decomposition(result)) for element in self.elements: print("\nElement: ", element) @@ -85,9 +87,12 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h # Just realised I don't have a spatial.unassign_container, but if so we'd do it here pass for added_element in element_set - subelements: - ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) + if added_element.is_a("IfcSpatialElement") or added_element.is_a("IfcSpatialStructureElement"): + ifcopenshell.api.run("aggregate.assign_object", self.file, product=added_element, relating_object=result) + else: + ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) print("assigned container") - results.append(result) + results.append(result.id()) return results def repeat_input_unique(self, input, count): diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index 8db13b6f61..ce70168445 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -79,6 +79,10 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. if self.refresh_local or hash(self) not in self.node_dict: self.file = SvIfcStore.get_file() + try: + self.entities = [self.file.by_id(step_id) for step_id in self.entities] + except Exception as e: + raise blender_objects = self.create() self.node_dict[hash(self)] = blender_objects else: From c72031fa5dd509f4864d6d89285babf81d43eaa6 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 31 Oct 2022 00:25:45 +0100 Subject: [PATCH 16/21] added blender panel for saving file + minor fix in create_entity --- src/ifcsverchok/__init__.py | 64 +++++++++++++++++++++- src/ifcsverchok/nodes/ifc/create_entity.py | 14 +++-- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 29c84a109f..0c21d4f9fc 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -42,7 +42,6 @@ from sverchok.utils.extra_categories import ( from sverchok.ui.nodeview_space_menu import make_extra_category_menus from sverchok.utils.logging import info, debug - def nodes_index(): return [ ( @@ -94,7 +93,65 @@ imported_modules = make_node_list() reload_event = False import bpy +import os +from os.path import abspath, splitext +import ifcopenshell +from ifcsverchok.ifcstore import SvIfcStore +from sverchok.data_structure import flatten_data +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") + + @classmethod + def poll(cls, context): + return any("IFC" in n for n in context.space_data.edit_tree.nodes.keys()) + + 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: + if not (self.file.by_type("IfcSpatialElement") or self.file.by_type("IfcSpatialStructureElement")): + print("No Ifc Spatial Element found. Adding all elements to IfcBuilding.") + elements = self.file.by_type("IfcElement") + building = ifcopenshell.api.run("root.create_entity", self.file, name="DefaultBuilding", ifc_class="IfcBuilding") + for element in elements: + ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=building) + self.file.write(self.filepath) + print(f"File written to: {self.filepath}") + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + +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): + layout = self.layout + row = layout.split(factor=0.2, align=True) + row = layout.row() + row.operator("ifc.write_file_panel") + +CLASSES = [IFC_Sv_write_file, IFC_PT_write_file_panel] def register_nodes(): node_modules = make_node_list() @@ -148,7 +205,8 @@ def register(): global our_menu_classes debug("Registering ifcsverchok") - + for klass in CLASSES: + bpy.utils.register_class(klass) register_nodes() extra_nodes = importlib.import_module(".nodes", "ifcsverchok") auto_gather_node_classes(extra_nodes) @@ -173,3 +231,5 @@ def unregister(): print(e) unregister_extra_category_provider("IFCSVERCHOK") unregister_nodes() + for klass in CLASSES: + bpy.utils.unregister_class(klass) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 4ae62b1394..da060ee868 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -1,6 +1,5 @@ import bpy - -# from helper import SayHello +from mathutils import Matrix import ifcopenshell import ifcsverchok.helper from ifcsverchok.ifcstore import SvIfcStore @@ -62,7 +61,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper def process(self): print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - + self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] @@ -139,12 +138,15 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper try: entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.ifc_class, name=self.names[i], description=self.descriptions[i]) try: - ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) + print("representations[i]: ", self.representations[i]) + if self.representations[i]: + ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) except IndexError: pass try: - print("LOCATION[i]: ", self.locations[i]) - ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) + if isinstance(self.locations[i], Matrix): + print("LOCATION[i]: ", self.locations[i], type(self.locations[i])) + ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) except IndexError: pass entities_ids.append(entity.id()) From 13a97babd8a319a23fee00b0c8b5cb7bdf72d3d1 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 31 Oct 2022 18:50:17 +0100 Subject: [PATCH 17/21] new pick_ifc_class node + minor fixes. Add_spatial_element is WIP --- src/ifcsverchok/__init__.py | 1 + .../nodes/ifc/add_spatial_element.py | 47 ++++++-- src/ifcsverchok/nodes/ifc/by_type.py | 26 +++-- src/ifcsverchok/nodes/ifc/create_entity.py | 14 ++- src/ifcsverchok/nodes/ifc/pick_ifc_class.py | 110 ++++++++++++++++++ 5 files changed, 177 insertions(+), 21 deletions(-) create mode 100644 src/ifcsverchok/nodes/ifc/pick_ifc_class.py diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 0c21d4f9fc..7a376eb856 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -53,6 +53,7 @@ def nodes_index(): ("ifc.create_entity", "SvIfcCreateEntity"), ("ifc.create_shape", "SvIfcCreateShape"), ("ifc.read_entity", "SvIfcReadEntity"), + ("ifc.pick_ifc_class", "SvIfcPickIfcClass"), ("ifc.by_id", "SvIfcById"), ("ifc.by_guid", "SvIfcByGuid"), ("ifc.by_type", "SvIfcByType"), diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index 24d1aa6f02..d474e9b309 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -16,26 +16,33 @@ from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_le class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcAddSpatialElement" bl_label = "IFC Add Spatial Element" + node_dict = {} + + n_id: StringProperty() Name: StringProperty(name="Name(s)", update=updateNode) IfcClass: StringProperty(name="IFC Class", update=updateNode, default="IfcSpace") Elements: StringProperty(name="Elements", update=updateNode) len_elements = 0 def sv_init(self, context): - self.inputs.new("SvStringsSocket", "Name(s)").prop_name = "Name" + self.inputs.new("SvStringsSocket", "Names").prop_name = "Name" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" self.outputs.new("SvStringsSocket", "Entities") - self.outputs.new("SvStringsSocket", "file") def process(self): + print("#"*20, "\n running add_spatial_element PROCESS()... \n", "#"*20,) + print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) if not any(socket.is_linked for socket in self.outputs): return - self.names = flatten_data(self.inputs["Name(s)"].sv_get(), target_level=1) - self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] + self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) + self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[0] self.elements = ensure_min_nesting(self.inputs["Elements"].sv_get(), 2) self.elements = flatten_data(self.elements, target_level=2) + if not self.elements[0][0]: + raise Exception('Mandatory input "Element(s)" is missing.') + return print("elements: ", self.elements) self.file = SvIfcStore.get_file() self.elements = [[self.file.by_id(step_id) for step_id in element] for element in self.elements] @@ -44,16 +51,35 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h print("elements: ", self.elements) self.names = self.repeat_input_unique(self.names, len(self.elements)) print("Names: ",self.names) + print("IfcClass: ",self.ifc_class) + + self.sv_input_names = [i.name for i in self.inputs] + if hash(self) not in self.node_dict: + self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict[hash(self)]: + self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + + print("node_dict: ", self.node_dict) + edit = False + for i in range(len(self.inputs)): + input = self.inputs[i].sv_get(deepcopy=False) + if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: + edit = True + print("Edit = True") + self.node_dict[hash(self)][self.inputs[i].name] = input + if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.len_elements): print("\nRunning create") elements = self.create() self.len_elements = len(self.elements) else: - elements = self.edit() + if edit is True: + elements = self.edit() + else: + elements = SvIfcStore.id_map[self.node_id] print("\n ##### results: ", elements) self.outputs["Entities"].sv_set(elements) - self.outputs["file"].sv_set([self.file]) def create(self): results = [] @@ -74,10 +100,14 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h def edit(self): results = [] results_ids = SvIfcStore.id_map[self.node_id] + print("#"*20, "\n running add_spatial_element edit()... \n", "#"*20,) + print("#"*20, "\n results_ids:", results_ids, "\n", "#"*20,) for result_id in results_ids: result = self.file.by_id(result_id) + print("#"*20, "\n result", result, "\n", "#"*20,) subelements = set(ifcopenshell.util.element.get_decomposition(result)) for element in self.elements: + print("\n\n\n","#"*50) print("\nElement: ", element) element_set = set(element) print("\nRESULT: ", result) @@ -85,7 +115,10 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h print("elements_set: ", element_set) for removed_element in subelements - element_set: # Just realised I don't have a spatial.unassign_container, but if so we'd do it here - pass + if removed_element.is_a("IfcSpatialElement") or removed_element.is_a("IfcSpatialStructureElement"): + ifcopenshell.api.run("aggregate.unassign_object", self.file, product=removed_element, relating_object=result) + else: + pass for added_element in element_set - subelements: if added_element.is_a("IfcSpatialElement") or added_element.is_a("IfcSpatialStructureElement"): ifcopenshell.api.run("aggregate.assign_object", self.file, product=added_element, relating_object=result) diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index 901f275e9f..4498ae767d 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -23,7 +23,7 @@ import ifcsverchok.helper from bpy.props import StringProperty, EnumProperty from ifcsverchok.ifcstore import SvIfcStore from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode +from sverchok.data_structure import updateNode, flatten_data def get_ifc_products(self, context): @@ -103,17 +103,27 @@ class SvIfcByType(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc if self.file: self.ifc_products = get_ifc_products(self, bpy.context) self.ifc_classes = get_ifc_classes(self, bpy.context) - self.sv_input_names = ["ifc_product", "ifc_class", "custom_ifc_class"] - super().process() + # self.sv_input_names = ["ifc_product", "ifc_class", "custom_ifc_class"] + self.ifc_product = flatten_data(self.inputs["ifc_product"].sv_get(), target_level=1)[0] + self.ifc_class = flatten_data(self.inputs["ifc_class"].sv_get(), target_level=1)[0] + self.custom_ifc_class = flatten_data(self.inputs["custom_ifc_class"].sv_get(), target_level=1)[0] - def process_ifc(self, ifc_product, ifc_class, custom_ifc_class): - if custom_ifc_class: - self.outputs["Entity"].sv_set([self.file.by_type(custom_ifc_class)]) - elif ifc_class: - self.outputs["Entity"].sv_set([self.file.by_type(ifc_class)]) + # super().process() + if self.custom_ifc_class: + self.outputs["Entity"].sv_set([self.file.by_type(self.custom_ifc_class)]) + elif self.ifc_class: + self.outputs["Entity"].sv_set([self.file.by_type(self.ifc_class)]) else: self.outputs["Entity"].sv_set([]) + # def process_ifc(self, ifc_product, ifc_class, custom_ifc_class): + # if custom_ifc_class: + # self.outputs["Entity"].sv_set([self.file.by_type(custom_ifc_class)]) + # elif ifc_class: + # self.outputs["Entity"].sv_set([self.file.by_type(ifc_class)]) + # else: + # self.outputs["Entity"].sv_set([]) + def register(): bpy.utils.register_class(SvIfcByType) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index da060ee868..4328c57dd8 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -1,5 +1,5 @@ import bpy -from mathutils import Matrix +from mathutils import Matrix, Vector import ifcopenshell import ifcsverchok.helper from ifcsverchok.ifcstore import SvIfcStore @@ -64,7 +64,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) - self.ifc_class = self.inputs["IfcClass"].sv_get()[0][0] + self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[0] self.representations = flatten_data(self.inputs["Representations"].sv_get(), target_level=1) self.locations = flatten_data(self.inputs["Locations"].sv_get(default=[]), target_level=1) self.properties = self.inputs["Properties"].sv_get() @@ -78,7 +78,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) print("node_dict: ", self.node_dict) if not self.inputs["IfcClass"].sv_get()[0][0]: - raise Exception("Insert IfcClass") + raise Exception('Mandatory input "IfcClass" is missing.') return edit = False @@ -109,7 +109,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.descriptions = self.repeat_input_unique(self.descriptions, len(self.names)) # print("REPRESENTATION: ", self.representations) - # print("IfcClass: ",self.ifc_class) + print("IfcClass: ", self.ifc_class) print("Names: ",self.names) print("Descriptions: ",self.descriptions) # print("\nrepresentations after convert: ", self.representations) @@ -144,6 +144,7 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper except IndexError: pass try: + print("IS INSTANCE MATRIX: ", isinstance(self.locations[i], Matrix), isinstance(self.locations[i], Vector)) if isinstance(self.locations[i], Matrix): print("LOCATION[i]: ", self.locations[i], type(self.locations[i])) ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) @@ -177,8 +178,9 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper except IndexError: pass try: - print("LOCATION[i]: ", self.locations[i]) - ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) + if isinstance(self.locations[i], Matrix): + print("LOCATION[i]: ", self.locations[i]) + ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) except IndexError: pass if entity.is_a() != self.ifc_class: diff --git a/src/ifcsverchok/nodes/ifc/pick_ifc_class.py b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py new file mode 100644 index 0000000000..6b4fd5bd4b --- /dev/null +++ b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py @@ -0,0 +1,110 @@ + +# IfcSverchok - IFC Sverchok extension +# Copyright (C) 2020, 2021 Dion Moult +# +# 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 . + +import bpy +import ifcopenshell +import ifcsverchok.helper +from bpy.props import StringProperty, EnumProperty +from ifcsverchok.ifcstore import SvIfcStore +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +def get_ifc_products(self, context): + ifc_products = getattr(self, "ifc_products", []) + file = SvIfcStore.get_file() + if not file: + return [] + if ifc_products and file: + return ifc_products + ifc_products = [] + ifc_products.extend( + [ + (e, e, "") + for e in [ + "IfcElement", + "IfcElementType", + "IfcSpatialElement", + "IfcGroup", + "IfcStructuralItem", + "IfcContext", + "IfcAnnotation", + ] + ] + ) + if file.schema == "IFC2X3": + ifc_products[2] = ("IfcSpatialStructureElement", "IfcSpatialStructureElement", "") + return ifc_products + + +def update_ifc_products(self, context): + if hasattr(self, "ifc_classes"): + self.ifc_classes.clear() + + +def get_ifc_classes(self, context): + ifc_classes = getattr(self, "ifc_classes", []) + if ifc_classes: + return self.ifc_classes + file = SvIfcStore.get_file() + if not file: + return [] + schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema) + declaration = schema.declaration_by_name(self.ifc_product) + + def get_classes(declaration): + results = [] + if not declaration.is_abstract(): + results.append(declaration.name()) + for subtype in declaration.subtypes(): + results.extend(get_classes(subtype)) + return results + + classes = get_classes(declaration) + ifc_classes.extend([(c, c, "") for c in sorted(classes)]) + return ifc_classes + + +class SvIfcPickIfcClass(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): + bl_idname = "SvIfcPickIfcClass" + bl_label = "IFC Class Picker" + ifc_product: EnumProperty(items=get_ifc_products, name="IfcProduct", description="Pick an IfcProduct from drop-down.", update=update_ifc_products) + ifc_class: EnumProperty(items=get_ifc_classes, name="IfcClass", description="Pick an IfcClass from drop-down.", update=updateNode) + + def sv_init(self, context): + self.inputs.new("SvStringsSocket", "ifc_product").prop_name = "ifc_product" + self.inputs.new("SvStringsSocket", "ifc_class").prop_name = "ifc_class" + self.outputs.new("SvStringsSocket", "IfcClass") + self.width = 200 + + def draw_buttons(self, context, layout): + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Ifc Class Picker" + + def process(self): + # ifc_product = self.inputs["ifc_product"].sv_get() + ifc_class = self.inputs["ifc_class"].sv_get()[0][0] + self.outputs["IfcClass"].sv_set([ifc_class]) + + +def register(): + bpy.utils.register_class(SvIfcPickIfcClass) + + +def unregister(): + bpy.utils.unregister_class(SvIfcPickIfcClass) From 9f855c3a830dc43da25b8e42c00024e8224a2ccc Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 7 Nov 2022 15:45:28 +0100 Subject: [PATCH 18/21] major changes primarily to file creation/saving logic. Bug fix in create entity. Other.. this commit is way to big and unstructured. --- src/ifcsverchok/__init__.py | 95 ++++++++- src/ifcsverchok/ifcstore.py | 24 ++- .../nodes/ifc/add_spatial_element.py | 198 ++++++++++++------ src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 6 +- src/ifcsverchok/nodes/ifc/by_type.py | 30 +-- src/ifcsverchok/nodes/ifc/create_entity.py | 14 +- src/ifcsverchok/nodes/ifc/pick_ifc_class.py | 7 +- 7 files changed, 252 insertions(+), 122 deletions(-) diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index 7a376eb856..d01676e15c 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -41,6 +41,8 @@ from sverchok.utils.extra_categories import ( ) from sverchok.ui.nodeview_space_menu import make_extra_category_menus from sverchok.utils.logging import info, debug +import asyncio +import time def nodes_index(): return [ @@ -100,17 +102,88 @@ import ifcopenshell from ifcsverchok.ifcstore import SvIfcStore from sverchok.data_structure import flatten_data +class IFC_Sv_UpdateCurrent(bpy.types.Operator): + """Update current Sverchok node tree""" + bl_idname = "ifc.sverchok_update_current" + bl_label = "Update current node tree" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + node_group: bpy.props.StringProperty(default="") + force_mode: bpy.props.BoolProperty(default=False) + + def execute(self, context): + print("#"*10, "Update current node tree") + self.file = SvIfcStore.purge() + self.file = SvIfcStore.get_file() + self.file.write("/Users/martina/Documents/GSoC/CodeTests/IfcFileTest_7_11_purged.ifc") + node_tree = context.space_data.node_tree + if node_tree: + print("### \tupdate tree", node_tree) + if self.force_mode or node_tree.sv_process: + print("### \tforce update") + try: + bpy.context.window.cursor_set("WAIT") + node_tree.force_update() + finally: + bpy.context.window.cursor_set("DEFAULT") + print("### \tupdate tree done") + self.report({"INFO"}, "Node tree updated") + return {'FINISHED'} + 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") + node_group: bpy.props.StringProperty(default="") + force_mode: bpy.props.BoolProperty(default=False) @classmethod def poll(cls, context): return any("IFC" in n for n in context.space_data.edit_tree.nodes.keys()) + def ensure_hirarchy(self, file): + elements_in_buildings = [] + if not 0 <= 0 < len(file.by_type("IfcBuilding")): + 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) + elements_in_buildings.extend(elements) + + 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)): + elements = ifcopenshell.util.element.get_decomposition(spatial) + ifcopenshell.api.run("aggregate.assign_object", file, product=spatial, relating_object=file.by_type("IfcBuilding")[0]) + + elements_in_buildings_after = [] + for building in file.by_type("IfcBuilding"): + elements = ifcopenshell.util.element.get_decomposition(building) + elements_in_buildings_after.extend(elements) + + elements = file.by_type("IfcElement") + for element in elements: + if element not in elements_in_buildings: + ifcopenshell.api.run("spatial.assign_container", file, product=element, relating_structure=file.by_type("IfcBuilding")[0]) + + + for building in file.by_type("IfcBuilding"): + elements = ifcopenshell.util.element.get_decomposition(building) + if not building.Decomposes: + if not 0 <= 0 < len(file.by_type("IfcSite")): + ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site") + ifcopenshell.api.run("aggregate.assign_object", file, product=building, relating_object=file.by_type("IfcSite")[0]) + try: + if file.by_type("IfcSite")[0].Decomposes[0].RelatingObject.is_a("IfcProject"): + continue + except IndexError: + pass + ifcopenshell.api.run("aggregate.assign_object", file, product=file.by_type("IfcSite")[0], relating_object=file.by_type("IfcProject")[0]) + self.file = file + return + def execute(self, context): self.file = SvIfcStore.file if not self.file: @@ -119,16 +192,18 @@ class IFC_Sv_write_file(bpy.types.Operator): if not ext: raise Exception("Bad path. Provide a path to a file.") else: - if not (self.file.by_type("IfcSpatialElement") or self.file.by_type("IfcSpatialStructureElement")): - print("No Ifc Spatial Element found. Adding all elements to IfcBuilding.") - elements = self.file.by_type("IfcElement") - building = ifcopenshell.api.run("root.create_entity", self.file, name="DefaultBuilding", ifc_class="IfcBuilding") - for element in elements: - ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=building) + self.ensure_hirarchy(self.file) + print("### \thirarchy ensured") + # if not (self.file.by_type("IfcSpatialElement") or self.file.by_type("IfcSpatialStructureElement")): + # self.report({"INFO"},"No Ifc Spatial Element found. Adding all elements to IfcBuilding.") + # elements = self.file.by_type("IfcElement") + # building = ifcopenshell.api.run("root.create_entity", self.file, name="DefaultBuilding", ifc_class="IfcBuilding") + # for element in elements: + # ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=building) self.file.write(self.filepath) - print(f"File written to: {self.filepath}") + self.report({"INFO"}, f"File written to: {self.filepath}") return {"FINISHED"} - + def invoke(self, context, event): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} @@ -147,12 +222,14 @@ class IFC_PT_write_file_panel(bpy.types.Panel): return True def draw(self, context): + ng = context.space_data.node_tree layout = self.layout row = layout.split(factor=0.2, align=True) row = layout.row() + row.operator('ifc.sverchok_update_current', text='IFC Re-run all nodes') row.operator("ifc.write_file_panel") -CLASSES = [IFC_Sv_write_file, IFC_PT_write_file_panel] +CLASSES = [IFC_Sv_UpdateCurrent,IFC_Sv_write_file, IFC_PT_write_file_panel] def register_nodes(): node_modules = make_node_list() diff --git a/src/ifcsverchok/ifcstore.py b/src/ifcsverchok/ifcstore.py index c334e952fc..9efff80ec6 100644 --- a/src/ifcsverchok/ifcstore.py +++ b/src/ifcsverchok/ifcstore.py @@ -65,7 +65,9 @@ class SvIfcStore: if bpy.context.scene.unit_settings.system == 'IMPERIAL': #TODO change units to imperial pass - model = ifcopenshell.api.run("context.add_context", file, context_type="Model") + # model = ifcopenshell.api.run("context.add_context", file, context_type="Model") + model = ifcopenshell.util.representation.get_context(file, context="Model") + print("model: ", model) context = ifcopenshell.api.run( "context.add_context", file, @@ -74,17 +76,17 @@ class SvIfcStore: target_view="MODEL_VIEW", parent=model, ) - site = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site") - building = ifcopenshell.api.run( - "root.create_entity", file, ifc_class="IfcBuilding", name="My Building" - ) - building_storey = ifcopenshell.api.run( - "root.create_entity", file, ifc_class="IfcBuildingStorey", name="My Storey" - ) + # site = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site") + # building = ifcopenshell.api.run( + # "root.create_entity", file, ifc_class="IfcBuilding", name="My Building" + # ) + # building_storey = ifcopenshell.api.run( + # "root.create_entity", file, ifc_class="IfcBuildingStorey", name="My Storey" + # ) - ifcopenshell.api.run("aggregate.assign_object", file, product=site, relating_object=file.by_type("IfcProject")[0]) - ifcopenshell.api.run("aggregate.assign_object", file, product=building, relating_object=site) - ifcopenshell.api.run("aggregate.assign_object", file, product=building_storey, relating_object=building) + # ifcopenshell.api.run("aggregate.assign_object", file, product=site, relating_object=file.by_type("IfcProject")[0]) + # ifcopenshell.api.run("aggregate.assign_object", file, product=building, relating_object=site) + # ifcopenshell.api.run("aggregate.assign_object", file, product=building_storey, relating_object=building) SvIfcStore.file = file return SvIfcStore.file diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index d474e9b309..0dcf4dcc7d 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -4,10 +4,6 @@ import ifcopenshell import ifcsverchok.helper from ifcsverchok.ifcstore import SvIfcStore -import bpy -import json -import ifcopenshell - from bpy.props import StringProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_length, ensure_min_nesting @@ -16,25 +12,55 @@ from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_le class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcAddSpatialElement" bl_label = "IFC Add Spatial Element" - node_dict = {} + node_dict2 = {} - n_id: StringProperty() - Name: StringProperty(name="Name(s)", update=updateNode) + Names: StringProperty(name="Name(s)", update=updateNode) IfcClass: StringProperty(name="IFC Class", update=updateNode, default="IfcSpace") Elements: StringProperty(name="Elements", update=updateNode) - len_elements = 0 def sv_init(self, context): - self.inputs.new("SvStringsSocket", "Names").prop_name = "Name" + self.inputs.new("SvStringsSocket", "Names").prop_name = "Names" self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" self.outputs.new("SvStringsSocket", "Entities") + self.node_dict2[hash(self)] = {} + + def draw_buttons(self, context, layout): + layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Ifc entity by type." def process(self): print("#"*20, "\n running add_spatial_element PROCESS()... \n", "#"*20,) print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) + try: + print("SvIfcStore.id_map: ", SvIfcStore.id_map) + print("self-node_id: ",self.node_id) + print("#"*20, "\n node_dict2 before before... \n", self.node_dict2, "\n", "#"*20,) + except: + pass + self.sv_input_names = [i.name for i in self.inputs] + if hash(self) not in self.node_dict2: + self.node_dict2[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict2[hash(self)]: + self.node_dict2[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + + print("#"*20, "\n node_dict2 before... \n", self.node_dict2, "\n", "#"*20,) if not any(socket.is_linked for socket in self.outputs): return + edit = False + edit_elements = False + for i in range(len(self.inputs)): + print(f"current node_dict2 iter:{i}: ", self.node_dict2[hash(self)]) + input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=True, default =[]) + print("current input: ", input) + print("previous input: ", self.node_dict2[hash(self)][self.inputs[i].name]) + if isinstance(self.node_dict2[hash(self)][self.inputs[i].name], list) and input != self.node_dict2[hash(self)][self.inputs[i].name]: + edit = True + print("Edit = True") + if self.inputs[i].name == "Elements": + edit_elements = True + print("edit_elements = True") + self.node_dict2[hash(self)][self.inputs[i].name] = input.copy() + print("#"*20, "\n node_dict2 after... \n", self.node_dict2,"\n", "#"*20,) self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[0] @@ -47,86 +73,119 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h self.file = SvIfcStore.get_file() self.elements = [[self.file.by_id(step_id) for step_id in element] for element in self.elements] - print("len elements: ", len(self.elements)) + + if "len" not in self.node_dict2[hash(self)]: + self.node_dict2[hash(self)]["len"] = 0 + print("len elements: ", len(self.elements), "stored len_elements: ", self.node_dict2[hash(self)]["len"]) print("elements: ", self.elements) self.names = self.repeat_input_unique(self.names, len(self.elements)) print("Names: ",self.names) print("IfcClass: ",self.ifc_class) - - self.sv_input_names = [i.name for i in self.inputs] - if hash(self) not in self.node_dict: - self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads - if not self.node_dict[hash(self)]: - self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - - print("node_dict: ", self.node_dict) - edit = False - for i in range(len(self.inputs)): - input = self.inputs[i].sv_get(deepcopy=False) - if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: - edit = True - print("Edit = True") - self.node_dict[hash(self)][self.inputs[i].name] = input + print("node_dict2: ", self.node_dict2) - if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.len_elements): + if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.node_dict2[hash(self)]["len"]): print("\nRunning create") + self.remove() elements = self.create() - self.len_elements = len(self.elements) + self.node_dict2[hash(self)]["len"] = len(self.elements) + print("stored len_elements: ", self.node_dict2[hash(self)]["len"]) else: if edit is True: - elements = self.edit() + elements = self.edit(edit_elements) else: + print("No changes") elements = SvIfcStore.id_map[self.node_id] - print("\n ##### results: ", elements) + print("\n ##### spatial element results: ", elements) self.outputs["Entities"].sv_set(elements) - def create(self): - results = [] - for i, element in enumerate(self.elements): - print("element: ", element) + def create(self, index=None): + print("#"*20, "\n running add_spatial_element create()... \n", "#"*20,) + spatial_ids = [] + iterator = range(len(self.elements)) + if index is not None: + iterator = [index] + for i in iterator: + print("element: ", self.elements[i]) result = ifcopenshell.api.run("root.create_entity", self.file, name=self.names[i], ifc_class=self.ifc_class) - for items in element: + for items in self.elements[i]: print("items: ", items) if items.is_a("IfcSpatialElement") or items.is_a("IfcSpatialStructureElement"): ifcopenshell.api.run("aggregate.assign_object", self.file, product=items, relating_object=result) else: ifcopenshell.api.run("spatial.assign_container", self.file, product=items, relating_structure=result) - SvIfcStore.id_map[result.id()] = self.node_id - SvIfcStore.id_map.setdefault(self.node_id, []).append(result.id()) - results.append(result.id()) - return results + # SvIfcStore.id_map[result.id()] = self.node_id + SvIfcStore.id_map.setdefault(self.node_id, []).append(result.id()) + spatial_ids.append(result.id()) + return spatial_ids - def edit(self): - results = [] - results_ids = SvIfcStore.id_map[self.node_id] + def edit(self, edit_elements): + spatial_ids = [] + id_map = SvIfcStore.id_map[self.node_id] + id_map_copy = SvIfcStore.id_map[self.node_id].copy() print("#"*20, "\n running add_spatial_element edit()... \n", "#"*20,) - print("#"*20, "\n results_ids:", results_ids, "\n", "#"*20,) - for result_id in results_ids: + print("#"*20, "\n id_map:", id_map, "\n", "#"*20,) + for i, element in enumerate(self.elements): + try: + result_id = id_map_copy[i] + except IndexError: + id = self.create(index=i) + spatial_ids.append(id[0]) + continue result = self.file.by_id(result_id) print("#"*20, "\n result", result, "\n", "#"*20,) - subelements = set(ifcopenshell.util.element.get_decomposition(result)) - for element in self.elements: - print("\n\n\n","#"*50) - print("\nElement: ", element) - element_set = set(element) - print("\nRESULT: ", result) + result.Name = self.names[i] + if edit_elements: + subelements = ifcopenshell.util.element.get_decomposition(result) print("subelements: ", subelements) - print("elements_set: ", element_set) - for removed_element in subelements - element_set: - # Just realised I don't have a spatial.unassign_container, but if so we'd do it here - if removed_element.is_a("IfcSpatialElement") or removed_element.is_a("IfcSpatialStructureElement"): - ifcopenshell.api.run("aggregate.unassign_object", self.file, product=removed_element, relating_object=result) - else: - pass - for added_element in element_set - subelements: - if added_element.is_a("IfcSpatialElement") or added_element.is_a("IfcSpatialStructureElement"): - ifcopenshell.api.run("aggregate.assign_object", self.file, product=added_element, relating_object=result) - else: - ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) - print("assigned container") - results.append(result.id()) - return results + subelements = set(subelements) + print("subelements after: ", subelements) + for element in self.elements[i]: + print("\n\n\n","#"*50) + print("\nElement: ", element) + element_set = set([element]) + print("\nRESULT: ", result) + print("subelements: ", subelements) + print("elements_set: ", element_set) + for removed_element in subelements - element_set: + # Just realised I don't have a spatial.unassign_container, but if so we'd do it here + print("removed_element: ", removed_element) + if removed_element.is_a("IfcSpatialElement") or removed_element.is_a("IfcSpatialStructureElement"): + ifcopenshell.api.run("aggregate.unassign_object", self.file, product=removed_element, relating_object=result) + else: + # ifcopenshell.api.run("spatial.unassign_container", self.file, product=removed_element, relating_object=result) + self.unassign_container(removed_element) + for added_element in element_set - subelements: + print("added_element: ", added_element) + if added_element.is_a("IfcSpatialElement") or added_element.is_a("IfcSpatialStructureElement"): + ifcopenshell.api.run("aggregate.assign_object", self.file, product=added_element, relating_object=result) + else: + ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) + print("assigned container") + spatial_ids.append(result.id()) + SvIfcStore.id_map[self.node_id] = spatial_ids + return spatial_ids + + def unassign_container(self, product): + for rel in product.ContainedInStructure or []: + related_elements = list(rel.RelatedElements) + related_elements.remove(product) + if related_elements: + rel.RelatedElements = related_elements + ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel) + else: + self.file.remove(rel) + + def remove(self): + print("#"*20, "\n running add_spatial_element remove()... \n", "#"*20,) + if self.node_id in SvIfcStore.id_map: + print(SvIfcStore.id_map[self.node_id]) + for element_id in SvIfcStore.id_map[self.node_id]: + element = self.file.by_id(element_id) + print("\nremoving element: ", element) + self.file.write("/Users/martina/Documents/GSoC/CodeTests/IfcFileTest_6_11_before_remove.ifc") + ifcopenshell.api.run("root.remove_product", self.file, product=element) + del SvIfcStore.id_map[self.node_id] def repeat_input_unique(self, input, count): input = repeat_last_for_length(input, count, deepcopy=False) @@ -134,10 +193,13 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h input = [a if not (s:=sum(j == a for j in input[:i])) else f'{a}-{s+1}' for i, a in enumerate(input)] # add number to duplicates return input - def get_existing_element(self): - entity_id = list(SvIfcStore.id_map.keys())[list(SvIfcStore.id_map.values()).index(self.node_id)] - return self.file.by_id(entity_id) - + def sv_free(self): + try: + del SvIfcStore.id_map[self.node_id] + del self.node_dict2[hash(self)] + print('Node was deleted') + except KeyError or AttributeError: + pass def register(): bpy.utils.register_class(SvIfcAddSpatialElement) diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 344170d18d..664efbbc3e 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -48,7 +48,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help def refresh_node(self, context): if self.refresh_local: - self.process() + updateNode(self, context) self.refresh_local = False refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) @@ -114,10 +114,10 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help return edit = False for i in range(len(self.inputs)): - input = self.inputs[i].sv_get(deepcopy=False) + input = self.inputs[i].sv_get(deepcopy=True) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True - self.node_dict[hash(self)][self.inputs[i].name] = input + self.node_dict[hash(self)][self.inputs[i].name] = input.copy() blender_objects = self.inputs["blender_objects"].sv_get() self.file = SvIfcStore.get_file() diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index 4498ae767d..2222151759 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -24,9 +24,10 @@ from bpy.props import StringProperty, EnumProperty from ifcsverchok.ifcstore import SvIfcStore from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data - +from sverchok.utils.handle_blender_data import keep_enum_reference def get_ifc_products(self, context): + print("#"*20, "\n running get_ifc_products PROCESS()... \n", "#"*20,) ifc_products = getattr(self, "ifc_products", []) file = SvIfcStore.get_file() if not file: @@ -54,11 +55,12 @@ def get_ifc_products(self, context): def update_ifc_products(self, context): + print("#"*20, "\n by_type update_ifc_products()... \n", "#"*20,) if hasattr(self, "ifc_classes"): self.ifc_classes.clear() - def get_ifc_classes(self, context): + print("#"*20, "\n by_type get_ifc_classes()... \n", "#"*20,) ifc_classes = getattr(self, "ifc_classes", []) if ifc_classes: return self.ifc_classes @@ -103,27 +105,17 @@ class SvIfcByType(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfc if self.file: self.ifc_products = get_ifc_products(self, bpy.context) self.ifc_classes = get_ifc_classes(self, bpy.context) - # self.sv_input_names = ["ifc_product", "ifc_class", "custom_ifc_class"] - self.ifc_product = flatten_data(self.inputs["ifc_product"].sv_get(), target_level=1)[0] - self.ifc_class = flatten_data(self.inputs["ifc_class"].sv_get(), target_level=1)[0] - self.custom_ifc_class = flatten_data(self.inputs["custom_ifc_class"].sv_get(), target_level=1)[0] + self.sv_input_names = ["ifc_product", "ifc_class", "custom_ifc_class"] + super().process() - # super().process() - if self.custom_ifc_class: - self.outputs["Entity"].sv_set([self.file.by_type(self.custom_ifc_class)]) - elif self.ifc_class: - self.outputs["Entity"].sv_set([self.file.by_type(self.ifc_class)]) + def process_ifc(self, ifc_product, ifc_class, custom_ifc_class): + if custom_ifc_class: + self.outputs["Entity"].sv_set([self.file.by_type(custom_ifc_class)]) + elif ifc_class: + self.outputs["Entity"].sv_set([self.file.by_type(ifc_class)]) else: self.outputs["Entity"].sv_set([]) - # def process_ifc(self, ifc_product, ifc_class, custom_ifc_class): - # if custom_ifc_class: - # self.outputs["Entity"].sv_set([self.file.by_type(custom_ifc_class)]) - # elif ifc_class: - # self.outputs["Entity"].sv_set([self.file.by_type(ifc_class)]) - # else: - # self.outputs["Entity"].sv_set([]) - def register(): bpy.utils.register_class(SvIfcByType) diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 4328c57dd8..d9ff9b6586 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -16,8 +16,6 @@ from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_length -input_map = {} - class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcCreateEntity" @@ -48,7 +46,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.inputs.new("SvMatrixSocket", "Locations").is_mandatory=False self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" self.outputs.new("SvStringsSocket", "Entities") - self.outputs.new("SvStringsSocket", "file") # only for testing self.node_dict[hash(self)] = {} def draw_buttons(self, context, layout): @@ -85,12 +82,12 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper for i in range(len(self.inputs)): # if self.sv_input_names[i] == "Locations": # input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False, default = []) - input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False, default =[]) + input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=True, default =[]) # print("input: ", input) # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True - self.node_dict[hash(self)][self.inputs[i].name] = input + self.node_dict[hash(self)][self.inputs[i].name] = input.copy() if self.refresh_local: edit = True @@ -127,7 +124,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper print("SvIfcStore.id_map: ", SvIfcStore.id_map) self.outputs["Entities"].sv_set(entities) - self.outputs["file"].sv_set([[self.file]]) def create(self, index=None): entities_ids = [] @@ -171,10 +167,10 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper entity.Description = self.descriptions[i] try: - if self.representations[i] and not self.file.by_type("IFCPRODUCTDEFINITIONSHAPE"): - ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) - elif self.representations[i]: + if self.representations[i] and self.representations[i].is_a('IfcProductDefinitionShape'): entity.Representation = self.representations[i] + elif self.representations[i]: + ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) except IndexError: pass try: diff --git a/src/ifcsverchok/nodes/ifc/pick_ifc_class.py b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py index 6b4fd5bd4b..44bef18512 100644 --- a/src/ifcsverchok/nodes/ifc/pick_ifc_class.py +++ b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py @@ -24,8 +24,9 @@ from bpy.props import StringProperty, EnumProperty from ifcsverchok.ifcstore import SvIfcStore from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode +from sverchok.utils.handle_blender_data import keep_enum_reference - +@keep_enum_reference def get_ifc_products(self, context): ifc_products = getattr(self, "ifc_products", []) file = SvIfcStore.get_file() @@ -52,12 +53,12 @@ def get_ifc_products(self, context): ifc_products[2] = ("IfcSpatialStructureElement", "IfcSpatialStructureElement", "") return ifc_products - +@keep_enum_reference def update_ifc_products(self, context): if hasattr(self, "ifc_classes"): self.ifc_classes.clear() - +@keep_enum_reference def get_ifc_classes(self, context): ifc_classes = getattr(self, "ifc_classes", []) if ifc_classes: From 3361895e1db0b2308262ed3be70fb57e0ca3e152 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 7 Nov 2022 17:21:09 +0100 Subject: [PATCH 19/21] bmesh_to_ifc now creates separate representations for each distinct bmesh geometry --- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 58 +++++++++-------------- src/ifcsverchok/nodes/ifc/create_shape.py | 2 +- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 664efbbc3e..31a402beb5 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -53,10 +53,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help refresh_local: BoolProperty(name="Update Node", description="Update Node", update=refresh_node) - n_id: StringProperty() - flat_output: BoolProperty( - name="Flat output", description="Flatten output by list-joining level 1", - default=True, update=updateNode) context_types = [ ('Model', 'Model', 'Context type: Model', 0), ('Plan', 'Plan', 'Context type: Plan', 1), @@ -74,15 +70,10 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help ('GRAPH_VIEW', 'GRAPH_VIEW', 'Target View: GRAPH_VIEW', 2), ('SKETCH_VIEW', 'SKETCH_VIEW', 'Target View: SKETCH_VIEW', 3), ] - paradigms = [ - ('Tessellation', 'Tessellation', 'Geometry paradigm: Tessellation', 0), - ('Extrusion', 'Extrusion', 'Geometry paradigm: Extrusion', 1), - ] blender_objects: PointerProperty(name="Blender Mesh(es)", description="Blender Mesh Object(s)",update=updateNode, type=bpy.types.Object) context_type: EnumProperty(name="Context Type", description="Default: Model", default="Model",items=context_types,update=updateNode) context_identifier: EnumProperty(name="Context Identifier", description="Default: Body", default="Body", items=context_identifiers, update=updateNode) target_view: EnumProperty(name="Target View", description="Default: MODEL VIEW", default="MODEL_VIEW",items=target_views, update=updateNode) - paradigm: EnumProperty(name="Paradigm", description="Which geometry type to convert to. Choose between tessellation or extrusion. Default: Tessellation.",default="Tessellation",items=paradigms, update=updateNode) tooltip: StringProperty(name="Tooltip") @@ -90,7 +81,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.inputs.new("SvStringsSocket", "context_type").prop_name = "context_type" self.inputs.new("SvStringsSocket", "context_identifier").prop_name = "context_identifier" self.inputs.new("SvStringsSocket", "target_view").prop_name = "target_view" - self.inputs.new("SvStringsSocket", "paradigm").prop_name = "paradigm" self.inputs.new("SvObjectSocket", "blender_objects").prop_name = "blender_objects" #no prop for now self.outputs.new("SvVerticesSocket", "Representations") self.outputs.new("SvMatrixSocket", "Locations") @@ -102,7 +92,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help row.prop(self, 'is_interactive', icon='SCENE_DATA', icon_only=True) row.prop(self, 'refresh_local', icon='FILE_REFRESH') - def process(self): + def process(self): self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: @@ -122,10 +112,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help blender_objects = self.inputs["blender_objects"].sv_get() self.file = SvIfcStore.get_file() - #temporary - if self.paradigm == "Extrusion": - raise Exception("Extrusion not yet implemented.") - return if self.refresh_local: edit = True if self.node_id not in SvIfcStore.id_map: @@ -135,10 +121,9 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help self.edit() representations, locations = self.create(blender_objects) else: - # representations = self.get_existing_element() representations = SvIfcStore.id_map[self.node_id]["Representations"] locations = SvIfcStore.id_map[self.node_id]["Locations"] - + print("representations: ", representations) print("locations: ", locations) @@ -148,25 +133,29 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help def create(self, blender_objects): representations_ids = [] locations = [] - add_matrix = locations.extend if self.flat_output else locations.append for blender_object in blender_objects: - representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = blender_object, geometry=blender_object.data, context = self.get_context()) - if not representation: - raise Exception("Couldn't create representation. Possibly wrong context.") - representations_ids.append(representation.id()) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) - location = blender_object.matrix_world - print("\n", "#"*30, "location: ", location) - add_matrix(location) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(location) + if blender_object.type == 'MESH': + bpy.ops.object.select_all(action='DESELECT') + blender_object.select_set(True) + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.separate(type='LOOSE') + for obj in bpy.context.selected_objects: + representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = obj, geometry=obj.data, context = self.get_context()) + print("\n", "#"*30, "representation: ", representation) + if not representation: + raise Exception("Couldn't create representation. Possibly wrong context.") + representations_ids.append(representation.id()) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) + locations.append(blender_object.matrix_world) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(location) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.select_all(action='DESELECT') return representations_ids, locations def edit(self): - # results = self.get_existing_element() if "Representations" not in SvIfcStore.id_map[self.node_id]: return for step_id in SvIfcStore.id_map[self.node_id]["Representations"]: - #if self.file.by_id(step_id).is_a('IfcShapeRepresentation'): ifcopenshell.api.run("geometry.remove_representation", self.file, representation=self.file.by_id(step_id)) del SvIfcStore.id_map[self.node_id]["Representations"] del SvIfcStore.id_map[self.node_id]["Locations"] @@ -180,7 +169,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help def get_context(self): context = ifcopenshell.util.representation.get_context(self.file, self.context_type, self.context_identifier, self.target_view) - if not context: parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) if not parent: @@ -194,11 +182,10 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help target_view=self.target_view, parent=parent, ) - # SvIfcStore.id_map.setdefault(self.node_id, []).append(context.id()) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) - return context - + + def sv_free(self): try: self.file = SvIfcStore.get_file() @@ -223,12 +210,11 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help print('Node was deleted') except KeyError or AttributeError: pass - + def register(): bpy.utils.register_class(SvIfcBMeshToIfcRepr) - def unregister(): - bpy.utils.unregister_class(SvIfcBMeshToIfcRepr) \ No newline at end of file + bpy.utils.unregister_class(SvIfcBMeshToIfcRepr) diff --git a/src/ifcsverchok/nodes/ifc/create_shape.py b/src/ifcsverchok/nodes/ifc/create_shape.py index ce70168445..220cc2d6e4 100644 --- a/src/ifcsverchok/nodes/ifc/create_shape.py +++ b/src/ifcsverchok/nodes/ifc/create_shape.py @@ -69,7 +69,7 @@ class SvIfcCreateShape(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper. def draw_buttons(self, context, layout): row = layout.row(align=True) - row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Create Blender shape from Ifc Entity. Takes one or multiple Ifc Entities." + row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Create Blender shape from IfcEntity ID. Takes one or multiple IfcEntity IDs." row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): From 9bf6cb953f2a3da372156bb491c69bd6fdfe3457 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 7 Nov 2022 17:40:18 +0100 Subject: [PATCH 20/21] write_file added logic that ensures proper model hierarchy --- src/ifcsverchok/__init__.py | 15 ++------ src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 3 +- src/ifcsverchok/nodes/ifc/write_file.py | 44 ++++++++++++++++++++++- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/ifcsverchok/__init__.py b/src/ifcsverchok/__init__.py index d01676e15c..a747a7aa34 100644 --- a/src/ifcsverchok/__init__.py +++ b/src/ifcsverchok/__init__.py @@ -118,16 +118,13 @@ class IFC_Sv_UpdateCurrent(bpy.types.Operator): self.file.write("/Users/martina/Documents/GSoC/CodeTests/IfcFileTest_7_11_purged.ifc") node_tree = context.space_data.node_tree if node_tree: - print("### \tupdate tree", node_tree) if self.force_mode or node_tree.sv_process: - print("### \tforce update") try: bpy.context.window.cursor_set("WAIT") node_tree.force_update() finally: bpy.context.window.cursor_set("DEFAULT") - print("### \tupdate tree done") - self.report({"INFO"}, "Node tree updated") + self.report({"INFO"}, "Node tree updated.") return {'FINISHED'} class IFC_Sv_write_file(bpy.types.Operator): @@ -193,13 +190,6 @@ class IFC_Sv_write_file(bpy.types.Operator): raise Exception("Bad path. Provide a path to a file.") else: self.ensure_hirarchy(self.file) - print("### \thirarchy ensured") - # if not (self.file.by_type("IfcSpatialElement") or self.file.by_type("IfcSpatialStructureElement")): - # self.report({"INFO"},"No Ifc Spatial Element found. Adding all elements to IfcBuilding.") - # elements = self.file.by_type("IfcElement") - # building = ifcopenshell.api.run("root.create_entity", self.file, name="DefaultBuilding", ifc_class="IfcBuilding") - # for element in elements: - # ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=building) self.file.write(self.filepath) self.report({"INFO"}, f"File written to: {self.filepath}") return {"FINISHED"} @@ -226,8 +216,9 @@ class IFC_PT_write_file_panel(bpy.types.Panel): layout = self.layout row = layout.split(factor=0.2, align=True) row = layout.row() + row2 = layout.row() row.operator('ifc.sverchok_update_current', text='IFC Re-run all nodes') - row.operator("ifc.write_file_panel") + row2.operator("ifc.write_file_panel") CLASSES = [IFC_Sv_UpdateCurrent,IFC_Sv_write_file, IFC_PT_write_file_panel] diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 31a402beb5..5fe56b0ba5 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -135,6 +135,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help locations = [] for blender_object in blender_objects: if blender_object.type == 'MESH': + bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') blender_object.select_set(True) bpy.ops.object.mode_set(mode='EDIT') @@ -147,7 +148,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help representations_ids.append(representation.id()) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) locations.append(blender_object.matrix_world) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(location) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Locations", []).append(blender_object.matrix_world) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') return representations_ids, locations diff --git a/src/ifcsverchok/nodes/ifc/write_file.py b/src/ifcsverchok/nodes/ifc/write_file.py index e2f7c51819..554ae811be 100644 --- a/src/ifcsverchok/nodes/ifc/write_file.py +++ b/src/ifcsverchok/nodes/ifc/write_file.py @@ -50,7 +50,7 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv def draw_buttons(self, context, layout): row = layout.row(align=True) - row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Writes active Ifc file to path.\n It will overwrite an existing file." + row.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Writes active Ifc file to path.\n It will overwrite an existing file.\n N.B.! It's recommended to create a fresh IFC File using the 're-run all nodes' button in IfcSverchok panel before saving." row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): @@ -63,8 +63,50 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv if not ext: raise Exception("Bad path. Provide a path to a file.") if self.refresh_local and ext: + self.ensure_hirarchy(file) file.write(path) self.outputs["output"].sv_set(f"File written successfully to: {path}.") + + def ensure_hirarchy(self, file): + elements_in_buildings = [] + if not 0 <= 0 < len(file.by_type("IfcBuilding")): + 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) + elements_in_buildings.extend(elements) + + 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)): + elements = ifcopenshell.util.element.get_decomposition(spatial) + ifcopenshell.api.run("aggregate.assign_object", file, product=spatial, relating_object=file.by_type("IfcBuilding")[0]) + + elements_in_buildings_after = [] + for building in file.by_type("IfcBuilding"): + elements = ifcopenshell.util.element.get_decomposition(building) + elements_in_buildings_after.extend(elements) + + elements = file.by_type("IfcElement") + for element in elements: + if element not in elements_in_buildings: + ifcopenshell.api.run("spatial.assign_container", file, product=element, relating_structure=file.by_type("IfcBuilding")[0]) + + + for building in file.by_type("IfcBuilding"): + elements = ifcopenshell.util.element.get_decomposition(building) + if not building.Decomposes: + if not 0 <= 0 < len(file.by_type("IfcSite")): + ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcSite", name="My Site") + ifcopenshell.api.run("aggregate.assign_object", file, product=building, relating_object=file.by_type("IfcSite")[0]) + try: + if file.by_type("IfcSite")[0].Decomposes[0].RelatingObject.is_a("IfcProject"): + continue + except IndexError: + pass + ifcopenshell.api.run("aggregate.assign_object", file, product=file.by_type("IfcSite")[0], relating_object=file.by_type("IfcProject")[0]) + self.file = file + return From d88adc23338de501f6413bcf941a86644d11cd02 Mon Sep 17 00:00:00 2001 From: martinaCodes Date: Mon, 7 Nov 2022 18:08:27 +0100 Subject: [PATCH 21/21] cleaned print statements etc --- .../nodes/ifc/add_spatial_element.py | 89 +++---------------- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 2 - src/ifcsverchok/nodes/ifc/by_type.py | 3 - src/ifcsverchok/nodes/ifc/create_entity.py | 22 ----- src/ifcsverchok/nodes/ifc/pick_ifc_class.py | 7 +- src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py | 7 +- 6 files changed, 17 insertions(+), 113 deletions(-) diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index 0dcf4dcc7d..228982facc 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -12,7 +12,7 @@ from sverchok.data_structure import updateNode, flatten_data, repeat_last_for_le class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): bl_idname = "SvIfcAddSpatialElement" bl_label = "IFC Add Spatial Element" - node_dict2 = {} + node_dict = {} Names: StringProperty(name="Name(s)", update=updateNode) IfcClass: StringProperty(name="IFC Class", update=updateNode, default="IfcSpace") @@ -23,44 +23,29 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h self.inputs.new("SvStringsSocket", "IfcClass").prop_name = "IfcClass" self.inputs.new("SvStringsSocket", "Elements").prop_name = "Elements" self.outputs.new("SvStringsSocket", "Entities") - self.node_dict2[hash(self)] = {} + self.node_dict[hash(self)] = {} def draw_buttons(self, context, layout): layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Ifc entity by type." def process(self): - print("#"*20, "\n running add_spatial_element PROCESS()... \n", "#"*20,) - print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) - try: - print("SvIfcStore.id_map: ", SvIfcStore.id_map) - print("self-node_id: ",self.node_id) - print("#"*20, "\n node_dict2 before before... \n", self.node_dict2, "\n", "#"*20,) - except: - pass self.sv_input_names = [i.name for i in self.inputs] - if hash(self) not in self.node_dict2: - self.node_dict2[hash(self)] = {} #happens if node is already on canvas when blender loads - if not self.node_dict2[hash(self)]: - self.node_dict2[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) + if hash(self) not in self.node_dict: + self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads + if not self.node_dict[hash(self)]: + self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - print("#"*20, "\n node_dict2 before... \n", self.node_dict2, "\n", "#"*20,) if not any(socket.is_linked for socket in self.outputs): return edit = False edit_elements = False for i in range(len(self.inputs)): - print(f"current node_dict2 iter:{i}: ", self.node_dict2[hash(self)]) input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=True, default =[]) - print("current input: ", input) - print("previous input: ", self.node_dict2[hash(self)][self.inputs[i].name]) - if isinstance(self.node_dict2[hash(self)][self.inputs[i].name], list) and input != self.node_dict2[hash(self)][self.inputs[i].name]: + if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True - print("Edit = True") if self.inputs[i].name == "Elements": edit_elements = True - print("edit_elements = True") - self.node_dict2[hash(self)][self.inputs[i].name] = input.copy() - print("#"*20, "\n node_dict2 after... \n", self.node_dict2,"\n", "#"*20,) + self.node_dict[hash(self)][self.inputs[i].name] = input.copy() self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) self.ifc_class = flatten_data(self.inputs["IfcClass"].sv_get(), target_level=1)[0] @@ -69,62 +54,43 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h if not self.elements[0][0]: raise Exception('Mandatory input "Element(s)" is missing.') return - print("elements: ", self.elements) self.file = SvIfcStore.get_file() self.elements = [[self.file.by_id(step_id) for step_id in element] for element in self.elements] - - if "len" not in self.node_dict2[hash(self)]: - self.node_dict2[hash(self)]["len"] = 0 - print("len elements: ", len(self.elements), "stored len_elements: ", self.node_dict2[hash(self)]["len"]) - print("elements: ", self.elements) + if "len" not in self.node_dict[hash(self)]: + self.node_dict[hash(self)]["len"] = 0 self.names = self.repeat_input_unique(self.names, len(self.elements)) - print("Names: ",self.names) - print("IfcClass: ",self.ifc_class) - print("node_dict2: ", self.node_dict2) - - if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.node_dict2[hash(self)]["len"]): - print("\nRunning create") + if (self.node_id not in SvIfcStore.id_map) or (len(self.elements) != self.node_dict[hash(self)]["len"]): self.remove() elements = self.create() - self.node_dict2[hash(self)]["len"] = len(self.elements) - print("stored len_elements: ", self.node_dict2[hash(self)]["len"]) + self.node_dict[hash(self)]["len"] = len(self.elements) else: if edit is True: elements = self.edit(edit_elements) else: - print("No changes") elements = SvIfcStore.id_map[self.node_id] - print("\n ##### spatial element results: ", elements) self.outputs["Entities"].sv_set(elements) def create(self, index=None): - print("#"*20, "\n running add_spatial_element create()... \n", "#"*20,) spatial_ids = [] iterator = range(len(self.elements)) if index is not None: iterator = [index] for i in iterator: - print("element: ", self.elements[i]) result = ifcopenshell.api.run("root.create_entity", self.file, name=self.names[i], ifc_class=self.ifc_class) for items in self.elements[i]: - print("items: ", items) if items.is_a("IfcSpatialElement") or items.is_a("IfcSpatialStructureElement"): ifcopenshell.api.run("aggregate.assign_object", self.file, product=items, relating_object=result) else: ifcopenshell.api.run("spatial.assign_container", self.file, product=items, relating_structure=result) - # SvIfcStore.id_map[result.id()] = self.node_id SvIfcStore.id_map.setdefault(self.node_id, []).append(result.id()) spatial_ids.append(result.id()) return spatial_ids def edit(self, edit_elements): spatial_ids = [] - id_map = SvIfcStore.id_map[self.node_id] id_map_copy = SvIfcStore.id_map[self.node_id].copy() - print("#"*20, "\n running add_spatial_element edit()... \n", "#"*20,) - print("#"*20, "\n id_map:", id_map, "\n", "#"*20,) for i, element in enumerate(self.elements): try: result_id = id_map_copy[i] @@ -133,57 +99,30 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h spatial_ids.append(id[0]) continue result = self.file.by_id(result_id) - print("#"*20, "\n result", result, "\n", "#"*20,) result.Name = self.names[i] if edit_elements: subelements = ifcopenshell.util.element.get_decomposition(result) - print("subelements: ", subelements) subelements = set(subelements) - print("subelements after: ", subelements) for element in self.elements[i]: - print("\n\n\n","#"*50) - print("\nElement: ", element) element_set = set([element]) - print("\nRESULT: ", result) - print("subelements: ", subelements) - print("elements_set: ", element_set) for removed_element in subelements - element_set: - # Just realised I don't have a spatial.unassign_container, but if so we'd do it here - print("removed_element: ", removed_element) if removed_element.is_a("IfcSpatialElement") or removed_element.is_a("IfcSpatialStructureElement"): ifcopenshell.api.run("aggregate.unassign_object", self.file, product=removed_element, relating_object=result) else: - # ifcopenshell.api.run("spatial.unassign_container", self.file, product=removed_element, relating_object=result) - self.unassign_container(removed_element) + ifcopenshell.api.run("spatial.unassign_container", self.file, product=removed_element, relating_object=result) for added_element in element_set - subelements: - print("added_element: ", added_element) if added_element.is_a("IfcSpatialElement") or added_element.is_a("IfcSpatialStructureElement"): ifcopenshell.api.run("aggregate.assign_object", self.file, product=added_element, relating_object=result) else: ifcopenshell.api.run("spatial.assign_container", self.file, product=added_element, relating_structure=result) - print("assigned container") spatial_ids.append(result.id()) SvIfcStore.id_map[self.node_id] = spatial_ids return spatial_ids - def unassign_container(self, product): - for rel in product.ContainedInStructure or []: - related_elements = list(rel.RelatedElements) - related_elements.remove(product) - if related_elements: - rel.RelatedElements = related_elements - ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel) - else: - self.file.remove(rel) - def remove(self): - print("#"*20, "\n running add_spatial_element remove()... \n", "#"*20,) if self.node_id in SvIfcStore.id_map: - print(SvIfcStore.id_map[self.node_id]) for element_id in SvIfcStore.id_map[self.node_id]: element = self.file.by_id(element_id) - print("\nremoving element: ", element) - self.file.write("/Users/martina/Documents/GSoC/CodeTests/IfcFileTest_6_11_before_remove.ifc") ifcopenshell.api.run("root.remove_product", self.file, product=element) del SvIfcStore.id_map[self.node_id] @@ -196,7 +135,7 @@ class SvIfcAddSpatialElement(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h def sv_free(self): try: del SvIfcStore.id_map[self.node_id] - del self.node_dict2[hash(self)] + del self.node_dict[hash(self)] print('Node was deleted') except KeyError or AttributeError: pass diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 5fe56b0ba5..426804d5d4 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -142,7 +142,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help bpy.ops.mesh.separate(type='LOOSE') for obj in bpy.context.selected_objects: representation = ifcopenshell.api.run("geometry.add_representation", self.file, should_run_listeners=False,blender_object = obj, geometry=obj.data, context = self.get_context()) - print("\n", "#"*30, "representation: ", representation) if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids.append(representation.id()) @@ -174,7 +173,6 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help parent = ifcopenshell.util.representation.get_context(self.file, self.context_type) if not parent: parent = ifcopenshell.api.run("context.add_context", self.file, context_type=self.context_type) - print("\nParent: ", parent) context = ifcopenshell.api.run( "context.add_context", self.file, diff --git a/src/ifcsverchok/nodes/ifc/by_type.py b/src/ifcsverchok/nodes/ifc/by_type.py index 2222151759..b6ed6bc7b1 100644 --- a/src/ifcsverchok/nodes/ifc/by_type.py +++ b/src/ifcsverchok/nodes/ifc/by_type.py @@ -27,7 +27,6 @@ from sverchok.data_structure import updateNode, flatten_data from sverchok.utils.handle_blender_data import keep_enum_reference def get_ifc_products(self, context): - print("#"*20, "\n running get_ifc_products PROCESS()... \n", "#"*20,) ifc_products = getattr(self, "ifc_products", []) file = SvIfcStore.get_file() if not file: @@ -55,12 +54,10 @@ def get_ifc_products(self, context): def update_ifc_products(self, context): - print("#"*20, "\n by_type update_ifc_products()... \n", "#"*20,) if hasattr(self, "ifc_classes"): self.ifc_classes.clear() def get_ifc_classes(self, context): - print("#"*20, "\n by_type get_ifc_classes()... \n", "#"*20,) ifc_classes = getattr(self, "ifc_classes", []) if ifc_classes: return self.ifc_classes diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index d9ff9b6586..0889fe1198 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -56,8 +56,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper row.prop(self, 'refresh_local', icon='FILE_REFRESH') def process(self): - print("#"*20, "\n running create_entity3 PROCESS()... \n", "#"*20,) - print("#"*20, "\n hash(self):", hash(self), "\n", "#"*20,) self.names = flatten_data(self.inputs["Names"].sv_get(), target_level=1) self.descriptions = flatten_data(self.inputs["Descriptions"].sv_get(), target_level=1) @@ -73,26 +71,18 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper self.node_dict[hash(self)] = {} #happens if node is already on canvas when blender loads if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - print("node_dict: ", self.node_dict) if not self.inputs["IfcClass"].sv_get()[0][0]: raise Exception('Mandatory input "IfcClass" is missing.') - return edit = False for i in range(len(self.inputs)): - # if self.sv_input_names[i] == "Locations": - # input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=False, default = []) input = self.inputs[self.sv_input_names[i]].sv_get(deepcopy=True, default =[]) - # print("input: ", input) - # print("self.node_dict[hash(self)][self.inputs[i].name]: ", self.node_dict[hash(self)][self.inputs[i].name]) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True self.node_dict[hash(self)][self.inputs[i].name] = input.copy() if self.refresh_local: edit = True - - print("\nrepresentations before convert: ", self.representations) self.file = SvIfcStore.get_file() if self.representations[0]: @@ -105,23 +95,15 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper elif not self.representations[0]: self.descriptions = self.repeat_input_unique(self.descriptions, len(self.names)) - # print("REPRESENTATION: ", self.representations) - print("IfcClass: ", self.ifc_class) - print("Names: ",self.names) - print("Descriptions: ",self.descriptions) - # print("\nrepresentations after convert: ", self.representations) - if self.node_id not in SvIfcStore.id_map: entities = self.create() else: if edit is True: entities = self.edit() else: - # entities = self.get_existing_element() entities = SvIfcStore.id_map[self.node_id] print("Entities: ", entities) - print("SvIfcStore.id_map: ", SvIfcStore.id_map) self.outputs["Entities"].sv_set(entities) @@ -134,15 +116,12 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper try: entity = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.ifc_class, name=self.names[i], description=self.descriptions[i]) try: - print("representations[i]: ", self.representations[i]) if self.representations[i]: ifcopenshell.api.run("geometry.assign_representation", self.file, product=entity, representation=self.representations[i]) except IndexError: pass try: - print("IS INSTANCE MATRIX: ", isinstance(self.locations[i], Matrix), isinstance(self.locations[i], Vector)) if isinstance(self.locations[i], Matrix): - print("LOCATION[i]: ", self.locations[i], type(self.locations[i])) ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) except IndexError: pass @@ -175,7 +154,6 @@ class SvIfcCreateEntity(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper pass try: if isinstance(self.locations[i], Matrix): - print("LOCATION[i]: ", self.locations[i]) ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=entity, matrix=self.locations[i]) except IndexError: pass diff --git a/src/ifcsverchok/nodes/ifc/pick_ifc_class.py b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py index 44bef18512..3b292d86c3 100644 --- a/src/ifcsverchok/nodes/ifc/pick_ifc_class.py +++ b/src/ifcsverchok/nodes/ifc/pick_ifc_class.py @@ -24,9 +24,7 @@ from bpy.props import StringProperty, EnumProperty from ifcsverchok.ifcstore import SvIfcStore from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode -from sverchok.utils.handle_blender_data import keep_enum_reference -@keep_enum_reference def get_ifc_products(self, context): ifc_products = getattr(self, "ifc_products", []) file = SvIfcStore.get_file() @@ -53,12 +51,12 @@ def get_ifc_products(self, context): ifc_products[2] = ("IfcSpatialStructureElement", "IfcSpatialStructureElement", "") return ifc_products -@keep_enum_reference + def update_ifc_products(self, context): if hasattr(self, "ifc_classes"): self.ifc_classes.clear() -@keep_enum_reference + def get_ifc_classes(self, context): ifc_classes = getattr(self, "ifc_classes", []) if ifc_classes: @@ -98,7 +96,6 @@ class SvIfcPickIfcClass(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper layout.operator("node.sv_ifc_tooltip", text="", icon="QUESTION", emboss=False).tooltip = "Ifc Class Picker" def process(self): - # ifc_product = self.inputs["ifc_product"].sv_get() ifc_class = self.inputs["ifc_class"].sv_get()[0][0] self.outputs["IfcClass"].sv_set([ifc_class]) diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index c95afbe148..925ce9ee41 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -89,13 +89,11 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - print("node_dict: ", self.node_dict) edit = False for i in range(len(self.inputs)): input = self.inputs[i].sv_get(deepcopy=False) if isinstance(self.node_dict[hash(self)][self.inputs[i].name], list) and input != self.node_dict[hash(self)][self.inputs[i].name]: edit = True - print("Edit = True") self.node_dict[hash(self)][self.inputs[i].name] = input self.vertices = self.inputs["Vertices"].sv_get(deepcopy=False) @@ -107,14 +105,13 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h representations = self.create(geo_data) else: - print("edit: ", edit) if edit is True: self.edit() representations = self.create(geo_data) else: # representations = self.get_existing_element() representations = SvIfcStore.id_map[self.node_id]["Representations"] - + self.outputs["Representation(s)"].sv_set(representations) def create(self, geo_data): @@ -133,7 +130,6 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") representations_ids.append(representation.id()) - print("Representation: ", representation) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Representations", []).append(representation.id()) return representations_ids @@ -164,7 +160,6 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h target_view=self.target_view, parent=parent, ) - print("context: ", context) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault("Contexts", []).append(context.id()) return context