Skip to content

Instantly share code, notes, and snippets.

@zeffii
Created June 11, 2022 17:55
Show Gist options
  • Save zeffii/c460abfada401e1daf5e9de9e8752d7a to your computer and use it in GitHub Desktop.
Save zeffii/c460abfada401e1daf5e9de9e8752d7a to your computer and use it in GitHub Desktop.
FCStd read node (unknown origin)
from sverchok.dependencies import FreeCAD
from sverchok.utils.dummy_nodes import add_dummy
from sverchok.utils.sv_operator_mixins import SvGenericNodeLocator
if FreeCAD is None:
add_dummy('SvReadFCStdNode', 'SvReadFCStdNode', 'FreeCAD')
else:
F = FreeCAD
import bpy
from mathutils import Matrix
from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.logging import info
from FreeCAD import Base
class SvReadFCStdOperator(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_read_fcstd_operator"
bl_label = "read freecad file"
bl_options = {'INTERNAL', 'REGISTER'}
def execute(self, context):
node = self.get_node(context)
if not node: return {'CANCELLED'}
if not any(socket.is_linked for socket in node.outputs):
return {'CANCELLED'}
if not node.inputs['File Path'].is_linked:
return {'CANCELLED'}
node.read_FCStd(node)
updateNode(node,context)
return {'FINISHED'}
class SvReadFCStdNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Read FreeCAD file
Tooltip: import parts from a .FCStd file
"""
bl_idname = 'SvReadFCStdNode'
bl_label = 'Read FCStd'
bl_icon = 'IMPORT'
solid_catergory = "Outputs"
read_update : BoolProperty(name="read_update", default=True)
read_body : BoolProperty(name="read_body", default=True, update = updateNode)
read_part : BoolProperty(name="read_part", default=True, update = updateNode)
tool_parts : BoolProperty(name="tool_parts", default=False, update = updateNode)
read_features : BoolProperty(name="read_features", default=False, update = updateNode)
inv_filter : BoolProperty(name="inv_filter", default=False, update = updateNode)
scale_factor : FloatProperty(name="unit factor", default=1, update = updateNode)
selected_label : StringProperty( default= 'Select FC Part')
selected_part : StringProperty( default='', update = updateNode)
merge_linked : BoolProperty(name="merge_linked", default=False, update = updateNode)
READ_ALL : BoolProperty(name="read all", default=False, update = updateNode)
def draw_buttons(self, context, layout):
col = layout.column(align=True)
if self.inputs['File Path'].is_linked:
self.wrapper_tracked_ui_draw_op(
col, SvShowFcstdNamesOp.bl_idname,
icon= 'TRIA_DOWN',
text= self.selected_label )
col.prop(self, 'read_update', text = 'global update')
col.prop(self, 'read_body')
col.prop(self, 'read_part')
col.prop(self, 'tool_parts')
if self.tool_parts:
col.prop(self, 'read_features')
col.prop(self, 'inv_filter')
col.prop(self, 'merge_linked')
col.prop(self,'READ_ALL')
col.prop(self, 'scale_factor')
self.wrapper_tracked_ui_draw_op(layout, SvReadFCStdOperator.bl_idname, icon='FILE_REFRESH', text="UPDATE")
def sv_init(self, context):
self.inputs.new('SvFilePathSocket', "File Path")
self.inputs.new('SvStringsSocket', "Label1 Filter")
self.inputs.new('SvStringsSocket', "Label2 Filter")
self.outputs.new('SvSolidSocket', "Solid")
def read_FCStd(self,node):
files = node.inputs['File Path'].sv_get()[0]
label_1_filter = []
label_2_filter = []
label_1_tags = []
label_2_tags = []
if node.inputs['Label1 Filter'].is_linked:
raw_filter = node.inputs['Label1 Filter'].sv_get()[0]
if len(raw_filter) == 1 and ',' in raw_filter[0]:
raw_filter = raw_filter[0].split(',')
for i in raw_filter:
if '#' in i:
label_1_tags.append(i)
else:
label_1_filter.append(i)
if node.inputs['Label2 Filter'].is_linked:
raw_filter = node.inputs['Label2 Filter'].sv_get()[0]
if len(raw_filter) == 1 and ',' in raw_filter[0]:
raw_filter = raw_filter[0].split(',')
for i in raw_filter:
if '#' in i:
label_2_tags.append(i)
else:
label_2_filter.append(i)
#ADD TO LABEL 1 FILTER THE DROPDOWN ENTRY IF SELECTED
if node.selected_part != '' and not node.selected_part in label_1_filter:
label_1_filter.append(node.selected_part)
solids = []
module_filter = []
if node.read_features:
module_filter.append('PartDesign')
if node.read_part:
module_filter.append('Part')
if node.read_body:
module_filter.append('PartDesign::Body')
for fname in files:
S = LoadSolid(
self.scale_factor, fname,
label_1_filter, label_1_tags, label_2_filter, label_2_tags,
module_filter, node.tool_parts,
node.inv_filter, self.READ_ALL, self.merge_linked )
for s in S:
solids.append(s)
node.outputs['Solid'].sv_set(solids)
def process(self):
if not any(socket.is_linked for socket in self.outputs):
return
if not self.inputs['File Path'].is_linked:
return
if self.read_update:
self.read_FCStd(self)
else:
return
class SvShowFcstdNamesOp(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_show_fcstd_names"
bl_label = "Show parts list"
bl_options = {'INTERNAL', 'REGISTER'}
bl_property = "option"
def LabelReader(self,context):
labels=[('','','')]
tree = bpy.data.node_groups[self.tree_name]
node = tree.nodes[self.node_name]
fc_file_list = node.inputs['File Path'].sv_get()[0]
module_filter = []
if node.read_features:
module_filter.append('PartDesign')
if node.read_part:
module_filter.append('Part')
if node.read_body:
module_filter.append('PartDesign::Body')
if node.merge_linked:
module_filter.append('App::Link')
for f in fc_file_list:
try:
F.open(f)
Fname = bpy.path.display_name_from_filepath(f)
F.setActiveDocument(Fname)
for obj in F.ActiveDocument.Objects:
if obj.Module in module_filter or obj.TypeId in module_filter:
labels.append( (obj.Label, obj.Label, obj.Label) )
except:
info('FCStd label read error')
finally:
F.closeDocument(Fname)
return labels
option : EnumProperty(items=LabelReader)
tree_name : StringProperty()
node_name : StringProperty()
def execute(self, context):
tree = bpy.data.node_groups[self.tree_name]
node = tree.nodes[self.node_name]
node.name_filter = self.option
node.selected_label = self.option
node.selected_part = self.option
bpy.context.area.tag_redraw()
return {'FINISHED'}
def invoke(self, context, event):
context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
wm = context.window_manager
wm.invoke_search_popup(self)
return {'FINISHED'}
def LoadSolid(
scale_factor, fc_file,
label_1_filter, label_1_tags, label_2_filter, label_2_tags,
module_filter, tool_parts,
inv_filter, READ_ALL, merge_linked):
objs= set()
sel_objs = set()
outList = set()
solids = set()
try:
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
F.setActiveDocument(Fname)
#PRE-FILTER FREECAD ENTITY BY TYPE_ID
#AVOID REIMPORT COMPOUND CHILDS
#for obj in F.ActiveDocument.Objects:
#if obj.TypeId == 'Part::Compound':
#for child in obj.Links:
#outList.add(child)
if merge_linked: module_filter.append('App::Link')
for obj in F.ActiveDocument.Objects:
#print ('START',obj)
'''
if merge_linked and obj.TypeId == 'App::Link':
if obj.LinkedObject.Module in ('Part', 'PartDesign'):
if len(obj.LinkedObject.Shape.Solids)>0:
try:
shapeobj = F.ActiveDocument.addObject(obj.LinkedObject.TypeId, obj.LinkedObject.Name + '_' + obj.Name )
M=F.Matrix();M.scale(1, 1, 1)#M.scale(scale_factor, scale_factor, scale_factor)
new_shape = obj.LinkedObject.Shape.transformGeometry(M)
new_shape.Placement = obj.Placement
shapeobj.Shape = new_shape
obj = shapeobj
except:
print ('ERROR',obj)
'''
if obj.Module in module_filter or obj.TypeId in module_filter:
objs.add (obj)
elif not tool_parts and obj.TypeId in ( 'Part::Cut','Part::Fuse','Part::MultiCommon','Part::Section','Part::FeaturePython' ):
if len(obj.OutList) > 0:
for out_obj in obj.OutList:
outList.add (out_obj)
objs = objs - outList
#SEARCH FOR TAGGED ITEM
if len(label_1_tags)>0:
for tag in label_1_tags:
for obj in objs:
if tag[1:] in obj.Label:
label_1_filter.append(obj.Label)
if len(label_2_tags)>0:
for tag in label_2_tags:
for obj in objs:
if tag[1:] in obj.Label2:
label_2_filter.append(obj.Label2)
for obj in objs:
if READ_ALL:
sel_objs.add( obj )
elif len(label_1_filter)>0:
if obj.Label in label_1_filter:
if len(label_2_filter)>0:
if obj.Label2 in label_2_filter:
sel_objs.add(obj)
else:
sel_objs.add(obj)
elif len(label_1_filter)==0 and len(label_2_filter)>0:
if obj.Label2 in label_2_filter: sel_objs.add(obj)
if inv_filter:
sel_objs = objs - sel_objs
for obj in sel_objs:
'''
if obj.TypeId == 'App::Link':
M=F.Matrix(); M.scale(scale_factor, scale_factor, scale_factor)
new_shape = obj.LinkedObject.Shape.transformGeometry(M)
new_shape.Placement = obj.Placement
solids.add( new_shape )
'''
if scale_factor != 1:
if len(obj.Shape.Solids)>0:
M=F.Matrix(); M.scale(scale_factor, scale_factor, scale_factor)
solids.add( obj.Shape.transformGeometry(M) )
else:
solids.add( obj.Shape )
except:
info('FCStd read error')
finally:
F.closeDocument(Fname)
return solids
def unitCheck(solid, scale_factor):
if len(solid.Solids)>0:
M=F.Matrix(); M.scale(scale_factor, scale_factor, scale_factor)
return solid.transformGeometry(M)
else:
return solid
def open_fc_file(fc_file):
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
F.setActiveDocument(Fname)
def register():
if FreeCAD is not None:
bpy.utils.register_class(SvReadFCStdNode)
bpy.utils.register_class(SvShowFcstdNamesOp)
bpy.utils.register_class(SvReadFCStdOperator)
def unregister():
if FreeCAD is not None:
bpy.utils.unregister_class(SvReadFCStdNode)
bpy.utils.unregister_class(SvShowFcstdNamesOp)
bpy.utils.register_class(SvReadFCStdOperator)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment