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)