Created
June 11, 2022 17:55
-
-
Save zeffii/c460abfada401e1daf5e9de9e8752d7a to your computer and use it in GitHub Desktop.
FCStd read node (unknown origin)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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