diff --git a/src/ifcsverchok/nodes/ifc/add_spatial_element.py b/src/ifcsverchok/nodes/ifc/add_spatial_element.py index 04c47a673f..3948bc1e17 100644 --- a/src/ifcsverchok/nodes/ifc/add_spatial_element.py +++ b/src/ifcsverchok/nodes/ifc/add_spatial_element.py @@ -18,6 +18,8 @@ import bpy +from itertools import chain + import ifcopenshell import ifcsverchok.helper from ifcsverchok.ifcstore import SvIfcStore @@ -99,7 +101,8 @@ class SvIfcAddSpatialElement( 0 ] self.elements = ensure_min_nesting(self.inputs["Elements"].sv_get(), 2) - self.elements = flatten_data(self.elements, target_level=2) + if isinstance(self.elements[0][0], list): + self.elements = [list(chain.from_iterable(el)) for el in self.elements] if not self.elements[0][0]: raise Exception('Mandatory input "Element(s)" is missing.') return diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index a0aaecaba7..054171ca46 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -142,7 +142,7 @@ class SvIfcBMeshToIfcRepr( if not self.node_dict[hash(self)]: self.node_dict[hash(self)].update(dict.fromkeys(self.sv_input_names, 0)) - if not self.inputs["blender_objects"].sv_get()[0]: + if not self.inputs["blender_objects"].sv_get(deepcopy=True)[0]: return edit = False for i in range(len(self.inputs)): @@ -154,7 +154,7 @@ class SvIfcBMeshToIfcRepr( edit = True self.node_dict[hash(self)][self.inputs[i].name] = input.copy() - blender_objects = self.inputs["blender_objects"].sv_get() + blender_objects = self.inputs["blender_objects"].sv_get(deepcopy=True) self.file = SvIfcStore.get_file() if self.refresh_local: @@ -169,60 +169,63 @@ class SvIfcBMeshToIfcRepr( representations = SvIfcStore.id_map[self.node_id]["Representations"] locations = SvIfcStore.id_map[self.node_id]["Locations"] - # print("representations: ", representations) - self.outputs["Representations"].sv_set(representations) self.outputs["Locations"].sv_set(locations) def create(self, blender_objects): representations_ids = [] locations = [] + context = self.get_context() for blender_object in blender_objects: - if blender_object.type == "MESH": - try: - bpy.ops.object.mode_set(mode="OBJECT") - except Exception as e: - print(e) - pass - bpy.ops.object.select_all(action="DESELECT") - try: - bpy.ops.object.mode_set(mode="EDIT") - except Exception as e: - print(e) - pass - blender_object.select_set(True) - bpy.ops.mesh.separate(type="LOOSE") - representations_ids_obj = [] - locations_obj = [] - for obj in bpy.context.selected_objects: + bpy.context.view_layer.objects.active = blender_object + try: + bpy.ops.object.mode_set(mode="OBJECT") + except Exception as e: + print(e) + pass + bpy.ops.object.select_all(action="DESELECT") + blender_object.select_set(True) + try: + bpy.ops.object.mode_set(mode="EDIT") + except Exception as e: + print(e) + pass + bpy.ops.mesh.separate( + type="LOOSE" + ) # This isn't a great solution bc it creates new objects in the scene, thus changing the users model + representations_ids_obj = [] + locations_obj = [] + try: + bpy.ops.object.mode_set(mode="OBJECT") + except Exception as e: + print(e) + pass + for obj in bpy.context.selected_objects: + if blender_object.type == "MESH": representation = ifcopenshell.api.run( "geometry.add_representation", self.file, should_run_listeners=False, blender_object=obj, geometry=obj.data, - context=self.get_context(), + context=context, ) if not representation: raise Exception( "Couldn't create representation. Possibly wrong context." ) - representations_ids_obj.append(representation.id()) - locations_obj.append(obj.matrix_world) - representations_ids.append(representations_ids_obj) - locations.append(locations_obj) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Representations", [] - ).append(representations_ids_obj) - SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( - "Locations", [] - ).append(locations_obj) - try: - bpy.ops.object.mode_set(mode="OBJECT") - except Exception as e: - print(e) - pass + representations_ids_obj.append([representation.id()]) + locations_obj.append([obj.matrix_world]) + representations_ids.append(representations_ids_obj) + locations.append(locations_obj) + + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( + "Representations", [] + ).append(representations_ids_obj) + SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( + "Locations", [] + ).append(locations_obj) bpy.ops.object.select_all(action="DESELECT") return representations_ids, locations @@ -234,7 +237,7 @@ class SvIfcBMeshToIfcRepr( ifcopenshell.api.run( "geometry.remove_representation", self.file, - representation=self.file.by_id(step_id), + representation=self.file.by_id(step_id[0]), ) del SvIfcStore.id_map[self.node_id]["Representations"] del SvIfcStore.id_map[self.node_id]["Locations"] @@ -291,7 +294,6 @@ class SvIfcBMeshToIfcRepr( 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)] diff --git a/src/ifcsverchok/nodes/ifc/create_entity.py b/src/ifcsverchok/nodes/ifc/create_entity.py index 2335e41527..71e44eb22f 100644 --- a/src/ifcsverchok/nodes/ifc/create_entity.py +++ b/src/ifcsverchok/nodes/ifc/create_entity.py @@ -69,8 +69,8 @@ class SvIfcCreateEntity( default="", update=updateNode, ) - # Locations: FloatVectorProperty(name="Locations", default="", update=updateNode) - Properties: StringProperty(name="properties", update=updateNode) + # Locations: FloatVectorProperty(name="Locations", default="", subtype='MATRIX', update=updateNode) + # Properties: StringProperty(name="properties", update=updateNode) def sv_init(self, context): self.inputs.new("SvStringsSocket", "Names").prop_name = "Names" @@ -80,7 +80,7 @@ class SvIfcCreateEntity( "SvStringsSocket", "Representations" ).prop_name = "Representations" self.inputs.new("SvMatrixSocket", "Locations").is_mandatory = False - self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" + # self.inputs.new("SvStringsSocket", "Properties").prop_name = "Properties" self.outputs.new("SvStringsSocket", "Entities") self.node_dict[hash(self)] = {} @@ -102,14 +102,15 @@ class SvIfcCreateEntity( 0 ] self.representations = ensure_min_nesting( - self.inputs["Representations"].sv_get(), 2 + self.inputs["Representations"].sv_get(), 3 ) - self.representations = flatten_data(self.representations, target_level=2) + self.representations = flatten_data(self.representations, target_level=3) self.locations = ensure_min_nesting( - self.inputs["Locations"].sv_get(default=[]), 2 + self.inputs["Locations"].sv_get(default=[]), 3 ) - self.properties = self.inputs["Properties"].sv_get() - + self.locations = flatten_data(self.locations, target_level=3) + # self.properties = self.inputs["Properties"].sv_get() + print("#" * 80, "\nCreate Entity", "\n", "#" * 80) self.sv_input_names = [i.name for i in self.inputs] if hash(self) not in self.node_dict: @@ -138,22 +139,35 @@ class SvIfcCreateEntity( self.file = SvIfcStore.get_file() if self.representations[0][0]: - try: - # self.representations = [self.file.by_id(step_id) for step_id in self.representations] - self.representations = [ - [self.file.by_id(step_id) for step_id in representation] - for representation 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][0]: + representations = [] + names = [] + descriptions = [] + for group in self.representations: + try: + group_representations = [ + [self.file.by_id(step_id) for step_id in representation] + for representation in group + ] + representations.append(group_representations) + except Exception as e: + raise + names.append( + self.repeat_input_unique(self.names, len(group_representations)) + ) + descriptions.append( + self.repeat_input_unique( + self.descriptions, len(group_representations) + ) + ) + self.representations = representations + self.names = names + self.descriptions = descriptions + elif not self.representations[0][0][0]: self.descriptions = self.repeat_input_unique( self.descriptions, len(self.names) ) + self.names = ensure_min_nesting(self.names, 3) + self.descriptions = ensure_min_nesting(self.descriptions, 3) if self.node_id not in SvIfcStore.id_map: entities = self.create() @@ -163,26 +177,75 @@ class SvIfcCreateEntity( else: entities = SvIfcStore.id_map[self.node_id] - # print("Entities: ", entities) self.outputs["Entities"].sv_set(entities) def create(self, index=None): entities_ids = [] - iterator = range(len(self.names)) - if index is not None: - iterator = [index] - for i in iterator: - try: - entity = ifcopenshell.api.run( - "root.create_entity", - self.file, - ifc_class=self.ifc_class, - name=self.names[i], - description=self.descriptions[i], - ) + for i, group in enumerate(self.names): + group_entities_ids = [] + iterator = range(len(group)) + if index is not None: + iterator = [index] + for j in iterator: + try: - for repr in self.representations[i]: - if repr: + entity = ifcopenshell.api.run( + "root.create_entity", + self.file, + ifc_class=self.ifc_class, + name=self.names[i][j], + description=self.descriptions[i][j], + ) + try: + for repr in self.representations[i][j]: + if repr: + ifcopenshell.api.run( + "geometry.assign_representation", + self.file, + product=entity, + representation=repr, + ) + except IndexError: + pass + try: + for loc in self.locations[i][j]: + print("Location: ", loc) + if isinstance(loc, Matrix): + ifcopenshell.api.run( + "geometry.edit_object_placement", + self.file, + product=entity, + matrix=loc, + ) + except IndexError: + pass + group_entities_ids.append(entity.id()) + except Exception as e: + raise Exception("Something went wrong. Cannot create entity.", e) + SvIfcStore.id_map.setdefault(self.node_id, []).append(group_entities_ids) + entities_ids.append(group_entities_ids) + return entities_ids + + def edit(self): + entities_ids = [] + id_map_copy = SvIfcStore.id_map[self.node_id].copy() + for i, group in enumerate(self.names): + group_entities_ids = [] + for j, _ in enumerate(group): + try: + step_id = id_map_copy[i][j] + except IndexError: + id = self.create(index=j) + group_entities_ids.append(id[0]) + continue + entity = self.file.by_id(step_id) + entity.Name = self.names[i][j] + entity.Description = self.descriptions[i][j] + try: + for repr in self.representations[i][j]: + if repr and repr.is_a("IfcProductDefinitionShape"): + entity.Representation = repr + elif repr: ifcopenshell.api.run( "geometry.assign_representation", self.file, @@ -192,7 +255,7 @@ class SvIfcCreateEntity( except IndexError: pass try: - for loc in self.locations[i]: + for loc in self.locations[i][j]: if isinstance(loc, Matrix): ifcopenshell.api.run( "geometry.edit_object_placement", @@ -202,60 +265,15 @@ class SvIfcCreateEntity( ) except IndexError: pass - 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 + if entity.is_a() != self.ifc_class: + SvIfcStore.id_map[self.node_id][i].remove(step_id) + entity = ifcopenshell.util.schema.reassign_class( + self.file, entity, self.ifc_class + ) + group_entities_ids.append(entity.id()) + entities_ids.append(group_entities_ids) - def edit(self): - entities_ids = [] - id_map_copy = SvIfcStore.id_map[self.node_id].copy() - 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] - - try: - for repr in self.representations[i]: - if repr and repr.is_a("IfcProductDefinitionShape"): - entity.Representation = repr - elif repr: - ifcopenshell.api.run( - "geometry.assign_representation", - self.file, - product=entity, - representation=repr, - ) - except IndexError: - pass - try: - for loc in self.locations[i]: - if isinstance(loc, Matrix): - ifcopenshell.api.run( - "geometry.edit_object_placement", - self.file, - product=entity, - matrix=loc, - ) - 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 - ) - 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 + SvIfcStore.id_map[self.node_id] = entities_ids return entities_ids def repeat_input_unique(self, input, count): diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index aa2cd88954..2703a94f83 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -162,7 +162,7 @@ class SvIfcSverchokToIfcRepr( raise Exception( "Couldn't create representation. Possibly wrong context." ) - representations_ids_obj.append(representation.id()) + representations_ids_obj.append([representation.id()]) representations_ids.append(representations_ids_obj) SvIfcStore.id_map.setdefault(self.node_id, {}).setdefault( "Representations", [] @@ -177,7 +177,7 @@ class SvIfcSverchokToIfcRepr( ifcopenshell.api.run( "geometry.remove_representation", self.file, - representation=self.file.by_id(step_id), + representation=self.file.by_id(step_id[0]), ) del SvIfcStore.id_map[self.node_id]["Representations"] return @@ -215,7 +215,7 @@ class SvIfcSverchokToIfcRepr( ifcopenshell.api.run( "geometry.remove_representation", self.file, - representation=self.file.by_id(step_id), + representation=self.file.by_id(step_id[0]), ) if "Contexts" in SvIfcStore.id_map[self.node_id]: diff --git a/src/ifcsverchok/nodes/ifc/write_file.py b/src/ifcsverchok/nodes/ifc/write_file.py index bbe4680298..d832d590cf 100644 --- a/src/ifcsverchok/nodes/ifc/write_file.py +++ b/src/ifcsverchok/nodes/ifc/write_file.py @@ -26,7 +26,9 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode, flatten_data -class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore): +class SvIfcWriteFile( + bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.SvIfcCore +): """ Triggers: Ifc write to file Tooltip: Write active Sverchok Ifc file to path @@ -37,11 +39,17 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv self.process() self.refresh_local = False - refresh_local: BoolProperty(name="Write", description="Write to file", update=refresh_node_local) + refresh_local: BoolProperty( + name="Write", description="Write to file", update=refresh_node_local + ) bl_idname = "SvIfcWriteFile" bl_label = "IFC Write File" - path: StringProperty(name="path", description="File path to write to. Can be relative.", 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", "path").prop_name = "path" @@ -71,18 +79,27 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv 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") + 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): + 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] + "aggregate.assign_object", + file, + product=spatial, + relating_object=file.by_type("IfcBuilding")[0], ) elements_in_buildings_after = [] @@ -94,19 +111,31 @@ class SvIfcWriteFile(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.helper.Sv 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] + "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( + "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] + "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"): + if ( + file.by_type("IfcSite")[0] + .Decomposes[0] + .RelatingObject.is_a("IfcProject") + ): continue except IndexError: pass