2022-08-25 22:01:35 +02:00
# IfcSverchok - IFC Sverchok extension
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcSverchok.
#
# IfcSverchok is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcSverchok is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IfcSverchok. If not, see <http://www.gnu.org/licenses/>.
2022-10-10 09:01:00 +02:00
from copy import deepcopy
2022-10-23 16:18:42 +02:00
from decimal import Context
2022-10-10 09:01:00 +02:00
from email . policy import default
2022-08-25 22:01:35 +02:00
import bpy
import ifcopenshell
import ifcsverchok . helper
import ifcopenshell . api
2022-10-10 09:01:00 +02:00
from ifcsverchok . ifcstore import SvIfcStore
2022-08-25 22:01:35 +02:00
import blenderbim . tool as tool
import blenderbim . core . geometry as core
2022-10-10 09:01:00 +02:00
from bpy . props import StringProperty , EnumProperty , IntProperty , BoolProperty , PointerProperty
2022-08-25 22:01:35 +02:00
from sverchok . node_tree import SverchCustomTreeNode
2022-10-10 09:01:00 +02:00
from sverchok . data_structure import ( updateNode , flatten_data , fixed_iter , flat_iter )
2022-08-25 22:01:35 +02:00
from blenderbim . bim . module . root . prop import get_contexts
2022-10-10 09:01:00 +02:00
from sverchok . data_structure import zip_long_repeat , node_id
from sverchok . core . socket_data import sv_get_socket
2022-08-25 22:01:35 +02:00
2022-10-10 09:01:00 +02:00
from itertools import chain , cycle
2022-08-25 22:01:35 +02:00
2022-10-10 09:01:00 +02:00
class SvIfcBMeshToIfcRepr ( bpy . types . Node , SverchCustomTreeNode , ifcsverchok . helper . SvIfcCore ) :
2022-08-25 22:01:35 +02:00
"""
2022-10-10 09:01:00 +02:00
Triggers: BMesh to Ifc Repr
Tooltip: Blender mesh to Ifc Shape Representation
2022-08-25 22:01:35 +02:00
"""
2022-10-10 09:01:00 +02:00
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 :
2022-11-07 15:45:28 +01:00
updateNode ( self , context )
2022-10-10 09:01:00 +02:00
self . refresh_local = False
refresh_local : BoolProperty ( name = " Update Node " , description = " Update Node " , update = refresh_node )
n_id : StringProperty ( )
2022-10-24 00:08:59 +02:00
flat_output : BoolProperty (
name = " Flat output " , description = " Flatten output by list-joining level 1 " ,
default = True , update = updateNode )
2022-10-10 09:01:00 +02:00
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 )
2022-08-25 22:01:35 +02:00
tooltip : StringProperty ( name = " Tooltip " )
2022-10-10 09:01:00 +02:00
2022-08-25 22:01:35 +02:00
def sv_init ( self , context ) :
2022-10-10 09:01:00 +02:00
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 " )
2022-10-24 00:08:59 +02:00
self . outputs . new ( " SvMatrixSocket " , " Locations " )
2022-10-23 16:18:42 +02:00
2022-08-25 22:01:35 +02:00
def draw_buttons ( self , context , layout ) :
2022-10-23 16:18:42 +02:00
layout . operator ( " node.sv_ifc_tooltip " , text = " " , icon = " QUESTION " , emboss = False ) . tooltip = " Blender mesh to Ifc Shape Representation. \n Takes one or multiple geometries. "
2022-10-10 09:01:00 +02:00
row = layout . row ( align = True )
row . prop ( self , ' is_interactive ' , icon = ' SCENE_DATA ' , icon_only = True )
row . prop ( self , ' refresh_local ' , icon = ' FILE_REFRESH ' )
2022-08-25 22:01:35 +02:00
2022-10-23 16:18:42 +02:00
def process ( self ) :
2022-10-10 09:01:00 +02:00
self . sv_input_names = [ i . name for i in self . inputs ]
2022-08-25 22:01:35 +02:00
2022-10-10 09:01:00 +02:00
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 ) )
if not self . inputs [ " blender_objects " ] . sv_get ( ) [ 0 ] :
return
edit = False
for i in range ( len ( self . inputs ) ) :
2022-11-07 15:45:28 +01:00
input = self . inputs [ i ] . sv_get ( deepcopy = True )
2022-10-10 09:01:00 +02:00
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
2022-11-07 15:45:28 +01:00
self . node_dict [ hash ( self ) ] [ self . inputs [ i ] . name ] = input . copy ( )
2022-10-10 09:01:00 +02:00
2022-10-23 16:18:42 +02:00
blender_objects = self . inputs [ " blender_objects " ] . sv_get ( )
self . file = SvIfcStore . get_file ( )
2022-10-10 09:01:00 +02:00
#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 :
2022-10-24 00:08:59 +02:00
representations , locations = self . create ( blender_objects )
2022-10-10 09:01:00 +02:00
else :
if edit is True :
self . edit ( )
2022-10-24 00:08:59 +02:00
representations , locations = self . create ( blender_objects )
2022-10-10 09:01:00 +02:00
else :
2022-10-21 00:11:45 +02:00
# representations = self.get_existing_element()
representations = SvIfcStore . id_map [ self . node_id ] [ " Representations " ]
2022-10-24 00:08:59 +02:00
locations = SvIfcStore . id_map [ self . node_id ] [ " Locations " ]
2022-10-10 09:01:00 +02:00
print ( " representations: " , representations )
2022-10-24 00:08:59 +02:00
print ( " locations: " , locations )
2022-10-10 09:01:00 +02:00
self . outputs [ " Representations " ] . sv_set ( representations )
2022-10-24 00:08:59 +02:00
self . outputs [ " Locations " ] . sv_set ( locations )
2022-10-10 09:01:00 +02:00
def create ( self , blender_objects ) :
2022-10-21 00:11:45 +02:00
representations_ids = [ ]
2022-10-24 00:08:59 +02:00
locations = [ ]
add_matrix = locations . extend if self . flat_output else locations . append
2022-10-10 09:01:00 +02:00
for blender_object in blender_objects :
2022-10-23 16:18:42 +02:00
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 ( ) )
2022-10-10 09:01:00 +02:00
if not representation :
raise Exception ( " Couldn ' t create representation. Possibly wrong context. " )
2022-10-21 00:11:45 +02:00
representations_ids . append ( representation . id ( ) )
2022-10-10 09:01:00 +02:00
SvIfcStore . id_map . setdefault ( self . node_id , { } ) . setdefault ( " Representations " , [ ] ) . append ( representation . id ( ) )
2022-10-24 00:08:59 +02:00
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
2022-10-10 09:01:00 +02:00
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 " ]
2022-10-24 00:08:59 +02:00
del SvIfcStore . id_map [ self . node_id ] [ " Locations " ]
2022-10-21 00:11:45 +02:00
return
2022-10-10 09:01:00 +02:00
def get_existing_element ( self ) :
results = [ ]
for step_id in SvIfcStore . id_map [ self . node_id ] [ " Representations " ] :
2022-10-21 00:11:45 +02:00
results . append ( self . file . by_id ( step_id ) )
2022-10-10 09:01:00 +02:00
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 ( " \n Parent: " , 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 ,
2022-08-25 22:01:35 +02:00
)
2022-10-10 09:01:00 +02:00
# 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 ) :
2022-08-25 22:01:35 +02:00
try :
2022-10-10 09:01:00 +02:00
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 ) )
2022-08-25 22:01:35 +02:00
2022-10-10 09:01:00 +02:00
if " Contexts " in SvIfcStore . id_map [ self . node_id ] :
for context_id in SvIfcStore . id_map [ self . node_id ] [ " Contexts " ] :
2022-10-23 16:18:42 +02:00
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 )
2022-10-10 09:01:00 +02:00
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
2022-08-25 22:01:35 +02:00
def register ( ) :
2022-10-10 09:01:00 +02:00
bpy . utils . register_class ( SvIfcBMeshToIfcRepr )
2022-08-25 22:01:35 +02:00
def unregister ( ) :
2022-10-10 09:01:00 +02:00
bpy . utils . unregister_class ( SvIfcBMeshToIfcRepr )