Не подтверждена Коммит 6b09bd34 создал по автору nikitron's avatar nikitron Зафиксировано автором GitHub
Просмотр файлов

Merge pull request #3674 from rastart/master

add FCStd read and write nodes
владельцы 6be04f3e 9cd424ad
FCStd Read (Exchange)
===========
Functionality
-------------
Parameters
----------
Inputs
------
Outputs
-------
Examples
--------
FCStd Sketch (Exchange)
===========
Functionality
-------------
Parameters
----------
Inputs
------
Outputs
-------
Examples
--------
\ No newline at end of file
FCStd Spreadsheet (Exchange)
===========
Functionality
-------------
Parameters
----------
Inputs
------
Outputs
-------
Examples
--------
\ No newline at end of file
FCStd Write (Exchange)
===========
Functionality
-------------
Parameters
----------
Inputs
------
Outputs
-------
Examples
--------
\ No newline at end of file
...@@ -10,4 +10,8 @@ Exchange ...@@ -10,4 +10,8 @@ Exchange
bezier_in bezier_in
nurbs_in nurbs_in
receive_from_sorcar receive_from_sorcar
gcode_exporter FCStd_sketch
\ No newline at end of file FCStd_spreadsheet
FCStd_write
FCStd_read
gcode_exporter
...@@ -675,7 +675,12 @@ ...@@ -675,7 +675,12 @@
SvExportSolidNode SvExportSolidNode
SvReceiveFromSorcarNode SvReceiveFromSorcarNode
SvExportGcodeNode SvExportGcodeNode
SvReadFCStdNode
SvWriteFCStdNode
SvReadFCStdSketchNode
SvFCStdSpreadsheetNode
SvApproxSubdtoNurbsNode
## Script ## Script
SvFormulaNodeMk5 SvFormulaNodeMk5
SvFormulaInterpolateNode SvFormulaInterpolateNode
......
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 bpy.props import StringProperty, BoolProperty, EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.logging import info
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)
selected_label : StringProperty( default= 'Select FC Part')
selected_part : StringProperty( default='', 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')
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', "Part Filter")
self.outputs.new('SvSolidSocket', "Solid")
def read_FCStd(self,node):
files = node.inputs['File Path'].sv_get()[0]
part_filter = []
if node.inputs['Part Filter'].is_linked:
part_filter = node.inputs['Part Filter'].sv_get()[0]
if node.selected_part != '' and not node.selected_part in part_filter:
part_filter.append(node.selected_part)
solids = []
obj_mask = []
if node.read_features:
obj_mask.append('PartDesign')
if node.read_part:
obj_mask.append('Part')
if node.read_body:
obj_mask.append('PartDesign::Body')
for f in files:
S = LoadSolid(f, part_filter, obj_mask, node.tool_parts, node.inv_filter)
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]
obj_mask = []
if node.read_features:
obj_mask.append('PartDesign')
if node.read_part:
obj_mask.append('Part')
if node.read_body:
obj_mask.append('PartDesign::Body')
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 obj_mask or obj.TypeId in obj_mask:
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(fc_file,part_filter,obj_mask,tool_parts, inv_filter):
objs= set()
outList = set()
solids = set()
try:
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
F.setActiveDocument(Fname)
for obj in F.ActiveDocument.Objects:
if obj.Module in obj_mask or obj.TypeId in obj_mask:
objs.add (obj)
if 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
for obj in objs:
if not inv_filter:
if obj.Label in part_filter or len(part_filter)==0:
solids.add(obj.Shape)
else:
if not obj.Label in part_filter:
solids.add(obj.Shape)
except:
info('FCStd read error')
finally:
F.closeDocument(Fname)
return solids
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)
\ No newline at end of file
from sverchok.dependencies import FreeCAD
from sverchok.utils.dummy_nodes import add_dummy
import mathutils
from sverchok.utils.sv_operator_mixins import SvGenericNodeLocator
if FreeCAD is None:
add_dummy('SvReadFCStdSketchNode', 'SvReadFCStdSketchNode', 'FreeCAD')
else:
F = FreeCAD
import bpy
import numpy as np
from bpy.props import StringProperty, IntProperty, BoolProperty, EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.logging import info
class SvReadFCStdSketchOperator(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_read_fcstd_sketch_operator"
bl_label = "read freecad sketch"
bl_options = {'INTERNAL', 'REGISTER'}
def execute(self, context):
node = self.get_node(context)
if not node: return {'CANCELLED'}
node.read_sketch(node)
updateNode(node,context)
return {'FINISHED'}
class SvReadFCStdSketchNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Read FreeCAD file
Tooltip: import parts from a .FCStd file
"""
bl_idname = 'SvReadFCStdSketchNode'
bl_label = 'Read FCStd Sketches'
bl_icon = 'IMPORT'
solid_catergory = "Outputs"
max_points : IntProperty(name="max_points", default=50, update = updateNode)
read_update : BoolProperty(name="read_update", default=True)
inv_filter : BoolProperty(name="inv_filter", default=False, update = updateNode)
selected_label : StringProperty(default='Select FC Part')
selected_part : StringProperty(default='',update = updateNode)
read_mode : EnumProperty(
name='mode',
description='read geometry / construction',
items=[
('geometry', 'geometry', 'geometry'),
('construction', 'construction', 'construction'),
('BOTH', 'BOTH', 'BOTH')],
default='geometry',
update = updateNode )
def draw_buttons(self, context, layout):
col = layout.column(align=True)
col.prop(self, 'read_mode')
if self.inputs['File Path'].is_linked:
self.wrapper_tracked_ui_draw_op(
col, SvShowFcstdSketchNamesOp.bl_idname,
icon= 'TRIA_DOWN',
text= self.selected_label )
col.prop(self, 'max_points')
col.prop(self, 'read_update')
col.prop(self, 'inv_filter')
self.wrapper_tracked_ui_draw_op(layout, SvReadFCStdSketchOperator.bl_idname, icon='FILE_REFRESH', text="UPDATE")
def sv_init(self, context):
self.inputs.new('SvFilePathSocket', "File Path")
self.inputs.new('SvStringsSocket', "Sketch Filter")
self.outputs.new('SvVerticesSocket', "Verts")
self.outputs.new('SvStringsSocket', "Edges")
self.outputs.new('SvCurveSocket', "Curve")
def read_sketch(self,node):
if not any(socket.is_linked for socket in node.outputs):
return
if not node.inputs['File Path'].is_linked:
return
if node.read_update:
files = node.inputs['File Path'].sv_get()[0]
sketch_filter = []
if node.inputs['Sketch Filter'].is_linked:
sketch_filter = node.inputs['Sketch Filter'].sv_get()[0]
if node.selected_part != '' and not node.selected_part in sketch_filter:
sketch_filter.append(node.selected_part)
Verts = []
Edges = []
curves_out = []
for f in files:
S = LoadSketch(f, sketch_filter, node.max_points, node.inv_filter, node.read_mode)
for i in S[0]:
Verts.append(i)
for i in S[1]:
Edges.append(i)
for i in S[2]:
curves_out.append(i)
node.outputs['Verts'].sv_set([Verts])
node.outputs['Edges'].sv_set([Edges])
node.outputs['Curve'].sv_set(curves_out)
else:
return
def process(self):
self.read_sketch(self)
class SvShowFcstdSketchNamesOp(bpy.types.Operator):
bl_idname = "node.sv_show_fcstd_sketch_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]
try:
for f in fc_file_list:
F.open(f)
Fname = bpy.path.display_name_from_filepath(f)
F.setActiveDocument(Fname)
for obj in F.ActiveDocument.Objects:
if obj.Module == 'Sketcher':
labels.append( (obj.Label, obj.Label, obj.Label) )
F.closeDocument(Fname)
except:
info('FCStd read error')
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 LoadSketch(fc_file, sketch_filter, max_points, inv_filter, read_mode):
import Part
sketches = []
Verts = []
Edges = []
Curves = []
#___________________GET FC FILE
try:
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
F.setActiveDocument(Fname)
except:
info('FCStd read error')
return (Verts,Edges,Curves)
#___________________SEARCH FOR SKETCHES
for obj in F.ActiveDocument.Objects:
if obj.Module == 'Sketcher':
if not inv_filter:
if obj.Label in sketch_filter or len(sketch_filter)==0:
sketches.append(obj)
else:
if not obj.Label in sketch_filter:
sketches.append(obj)
if len(sketches)==0:
return (Verts,Edges)
#__ search for max single perimeter in sketches geometry
#__ (to use as resampling reference)
max_len=set()
for s in sketches:
for g in s.Geometry:
if not isinstance(g, Part.Point ) :
max_len.add( g.length() )
max_len=max(max_len)
#___________________CONVERT SKETCHES GEOMETRY
for s in sketches:
#get sketch plane placement to local - global conversion
s_placement = s.Placement
if len(s.InList) > 0:
s_placement = s.InList[0].Placement.multiply( s_placement )
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> EVALUATE CURVE START
for i,geo in enumerate(s.Geometry):
if read_mode == 'geometry':
if s.getConstruction(i) : continue
#FREECAD 0.18 #if geo.Construction : continue
elif read_mode == 'construction':
if not s.getConstruction(i) : continue
#FREECAD 0.18 #if not geo.Construction : continue
v_set=[]
e_set=[]
#LINE CASE
if isinstance(geo, Part.LineSegment ):
geo_points = 2
#POINT CASE
elif isinstance(geo, Part.Point ):
geo_points = 1
else:
geo_points = int (max_points * geo.length() / max_len) + 1
if geo_points < 2:
geo_points = 2
if geo_points!=1:
verts = geo.discretize(Number = geo_points )
else:
verts = [ (geo.X,geo.Y,geo.Z) ]
for v in verts:
v_co = F.Vector( ( v[0], v[1], v[2] ) )
abs_co = FreeCAD_abs_placement(s_placement,v_co).Base
v_set.append ( (abs_co.x, abs_co.y, abs_co.z) )
for i in range ( len(v_set)-1 ):
v_count = len(Verts)
e_set.append ( (v_count+i,v_count+i+1) )
Verts.extend (v_set)
Edges.extend (e_set)
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< EVALUATE CURVE END
#-------------------------------------------------------------
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FC CURVE TO SV CURVE
#LINE
if isinstance(geo, Part.LineSegment ):
from sverchok.utils.curve import SvLine
point1 = np.array(v_set[0])
direction = np.array(v_set[1]) - point1
line = SvLine(point1, direction)
line.u_bounds = (0, 1)
Curves.append(line)
#CIRCLE
elif isinstance(geo, Part.Circle ) or isinstance(geo, Part.ArcOfCircle ):
from sverchok.utils.curve import SvCircle
from mathutils import Matrix
center = F.Vector( (geo.Location.x,geo.Location.y,geo.Location.z) )
c_placement = FreeCAD_abs_placement(s_placement,center)
placement_mat = c_placement.toMatrix()
b_mat = Matrix()
r=0; c=0
for i in placement_mat.A:
if c == 4:
r+=1; c=0
b_mat[r][c]=i
c+=1
curve = SvCircle(matrix=b_mat, radius=geo.Radius)
if isinstance(geo, Part.ArcOfCircle ):
curve.u_bounds = (geo.FirstParameter, geo.LastParameter)
Curves.append(curve)
elif geo_points!=1:
geo = geo.toNurbs()
from sverchok.utils.nurbs_common import SvNurbsMaths
from sverchok.utils.curve import SvNurbsCurve
abs_poles = []
for vec in geo.getPoles():
abs_co = FreeCAD_abs_placement(s_placement,vec).Base
abs_poles.append ( (abs_co.x, abs_co.y, abs_co.z) )
new_curve = SvNurbsCurve.build( SvNurbsMaths.FREECAD, geo.Degree, geo.KnotSequence, abs_poles, geo.getWeights() )
Curves.append(new_curve)
F.closeDocument(Fname)
return (Verts,Edges,Curves)
def FC_matrix_to_mathutils_format(fc_matrix):
row=0
col=0
b_matrix = mathutils.Matrix()
for i in fc_matrix.A:
if col == 4:
row += 1; col = 0
b_matrix[row][col] = i
col += 1
return b_matrix
def FreeCAD_abs_placement(sketch_placement,p_co):
p_co = F.Vector( ( p_co[0], p_co[1], p_co[2] ) )
local_placement = F.Placement()
local_placement.Base = p_co
return sketch_placement.multiply(local_placement)
def register():
if FreeCAD is not None:
bpy.utils.register_class(SvReadFCStdSketchNode)
bpy.utils.register_class(SvShowFcstdSketchNamesOp)
bpy.utils.register_class(SvReadFCStdSketchOperator)
def unregister():
if FreeCAD is not None:
bpy.utils.unregister_class(SvReadFCStdSketchNode)
bpy.utils.unregister_class(SvShowFcstdSketchNamesOp)
bpy.utils.unregister_class(SvReadFCStdSketchOperator)
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('SvFCStdSpreadsheetNode', 'SvFCStdSpreadsheetNode', 'FreeCAD')
else:
F = FreeCAD
import bpy
from bpy.props import StringProperty, IntProperty, BoolProperty, EnumProperty, FloatProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.logging import info
class SvFCStdSpreadsheetOperator(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_fcstd_spreadsheet_operator"
bl_label = "read/write freecad spreadsheet"
bl_options = {'INTERNAL', 'REGISTER'}
def execute(self, context):
node = self.get_node(context)
if not node: return {'CANCELLED'}
node.edit_spreadsheet(node)
updateNode(node,context)
return {'FINISHED'}
class SvFCStdSpreadsheetNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Read FreeCAD file
Tooltip: Read/write FCStd Spreadsheets from a .FCStd file
"""
bl_idname = 'SvFCStdSpreadsheetNode'
bl_label = 'Read/write Spreadsheets'
bl_icon = 'IMPORT'
solid_catergory = "Outputs"
auto_update : BoolProperty(name="auto_update", default=True)
write_update : BoolProperty(name="read_update", default=True)
write_parameter : BoolProperty(name="write_parameter", default=False)
selected_label : StringProperty(default='Spreadsheet')
selected_sheet : StringProperty(default='',update = updateNode)
selected_par_label : StringProperty(default='Parameter')
selected_par : StringProperty(default='',update = updateNode)
cell_in : FloatProperty( name="cell_in", description='cell_in', default=0.0 )
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, SvShowFcstdSpreadsheetsOp.bl_idname,
icon= 'TRIA_DOWN',
text= self.selected_label )
if self.inputs['File Path'].is_linked:
self.wrapper_tracked_ui_draw_op(
col, SvShowFcstdParNamesOp.bl_idname,
icon= 'TRIA_DOWN',
text= self.selected_par_label )
col.prop(self, 'auto_update')
col.prop(self, 'write_parameter')
self.wrapper_tracked_ui_draw_op(layout, SvFCStdSpreadsheetOperator.bl_idname, icon='FILE_REFRESH', text="UPDATE")
def sv_init(self, context):
self.inputs.new('SvFilePathSocket', "File Path")
self.inputs.new('SvStringsSocket', "cell_in").prop_name = 'cell_in'
self.outputs.new('SvStringsSocket', "cell_out")
def edit_spreadsheet(self,node):
if not node.inputs['File Path'].is_linked:
return
if node.selected_par != '' :
files = node.inputs['File Path'].sv_get()[0]
cell_out=None
for f in files:
cell_out = WriteParameter(
f,
node.selected_sheet,
node.selected_par,
node.inputs['cell_in'].sv_get()[0][0],
node.write_parameter)
if cell_out != None:
node.outputs['cell_out'].sv_set( [[cell_out]] )
else:
node.outputs['cell_out'].sv_set( [ ] )
return
def process(self):
if self.auto_update:
self.edit_spreadsheet(self)
class SvShowFcstdSpreadsheetsOp(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_show_fcstd_spreadsheets"
bl_label = "Show spreadsheet 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]
try:
for f in fc_file_list:
F.open(f)
Fname = bpy.path.display_name_from_filepath(f)
F.setActiveDocument(Fname)
for obj in F.ActiveDocument.Objects:
if obj.Module == 'Spreadsheet':
labels.append( (obj.Label, obj.Label, obj.Label) )
except:
info('LabelReader Spreadsheet 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_sheet = 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'}
class SvShowFcstdParNamesOp(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_show_fcstd_par_names"
bl_label = "Show parameter 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]
try:
for f in fc_file_list:
F.open(f)
Fname = bpy.path.display_name_from_filepath(f)
F.setActiveDocument(Fname)
for obj in F.ActiveDocument.Objects:
if obj.Label == node.selected_sheet:
props = obj.PropertiesList
for label in props:
alias = obj.getCellFromAlias(label)
if alias:
labels.append( (label, label, label) )
except:
info('Label reader read cell 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_par_label = self.option
node.selected_par = 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 WriteParameter(fc_file,spreadsheet,alias,par_write,write):
#___________________GET FC FILE
try:
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
F.setActiveDocument(Fname)
#___________________SEARCH FOR SKETCHES
cell_out = None
for obj in F.ActiveDocument.Objects:
if obj.Label == spreadsheet:
if alias in obj.PropertiesList:
cell = obj.getCellFromAlias(alias)
if write:
obj.set(cell,str(par_write))
F.ActiveDocument.recompute()
F.getDocument(Fname).save()
cell_out = obj.get(cell)
break
except:
info('WriteParameter error')
finally:
F.closeDocument(Fname)
return cell_out
def register():
if FreeCAD is not None:
bpy.utils.register_class(SvFCStdSpreadsheetNode)
bpy.utils.register_class(SvShowFcstdSpreadsheetsOp)
bpy.utils.register_class(SvShowFcstdParNamesOp)
bpy.utils.register_class(SvFCStdSpreadsheetOperator)
def unregister():
if FreeCAD is not None:
bpy.utils.unregister_class(SvFCStdSpreadsheetNode)
bpy.utils.unregister_class(SvShowFcstdSpreadsheetsOp)
bpy.utils.unregister_class(SvShowFcstdParNamesOp)
bpy.utils.unregister_class(SvFCStdSpreadsheetOperator)
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('SvWriteFCStdNode', 'SvWriteFCStdNode', 'FreeCAD')
else:
F = FreeCAD
import bpy
from bpy.props import StringProperty, BoolProperty,EnumProperty
from sverchok.node_tree import SverchCustomTreeNode # OLD throttled
from sverchok.data_structure import updateNode, match_long_repeat # NEW throttle_and_update_node
from sverchok.utils.logging import info
class SvWriteFCStdOperator(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.sv_write_fcstd_operator"
bl_label = "write freecad file"
bl_options = {'INTERNAL', 'REGISTER'}
def execute(self, context):
node = self.get_node(context)
if not node: return {'CANCELLED'}
node.write_FCStd(node)
updateNode(node,context)
return {'FINISHED'}
class SvWriteFCStdNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: write FreeCAD file
Tooltip: write parts in a .FCStd file
"""
bl_idname = 'SvWriteFCStdNode'
bl_label = 'Write FCStd'
bl_icon = 'IMPORT'
solid_catergory = "Inputs"
write_update : BoolProperty(
name="write_update",
default=False)
part_name : StringProperty(
name="part_name",
default="part_name")
#@throttled
def changeMode(self, context):
if self.obj_format == 'mesh':
if 'Verts' not in self.inputs:
self.inputs.remove(self.inputs['Solid'])
self.inputs.new('SvVerticesSocket', 'Verts')
self.inputs.new('SvVerticesSocket', 'Faces')
return
else:
if 'Solid' not in self.inputs:
self.inputs.remove(self.inputs['Verts'])
self.inputs.remove(self.inputs['Faces'])
self.inputs.new('SvSolidSocket', 'Solid')
return
obj_format : EnumProperty(
name='format',
description='choose format',
items={
('solid', 'solid', 'solid'),
('mesh', 'mesh', 'mesh')},
default='solid',
update=changeMode)
def draw_buttons(self, context, layout):
layout.label(text="write name:")
col = layout.column(align=True)
col.prop(self, 'part_name',text="")
col.prop(self, 'obj_format',text="")
col.prop(self, 'write_update')
if self.obj_format == 'mesh':
col.label(text="need triangle meshes")
self.wrapper_tracked_ui_draw_op(layout, SvWriteFCStdOperator.bl_idname, icon='FILE_REFRESH', text="UPDATE")
def sv_init(self, context):
self.inputs.new('SvFilePathSocket', "File Path")
if self.obj_format == 'mesh':
self.inputs.new('SvVerticesSocket', "Verts")
self.inputs.new('SvStringsSocket', "Faces")
else:
self.inputs.new('SvSolidSocket', 'Solid')
def write_FCStd(self,node):
if not node.inputs['File Path'].is_linked:
return
files = node.inputs['File Path'].sv_get()
if not len(files[0]) == 1:
print ('FCStd write node support just 1 file at once')
return
fc_file=files[0][0]
if node.obj_format == 'mesh':
if any((node.inputs['Verts'].is_linked,node.inputs['Faces'].is_linked)):
verts_in = node.inputs['Verts'].sv_get(deepcopy=False)
pols_in = node.inputs['Faces'].sv_get(deepcopy=False)
verts, pols = match_long_repeat([verts_in, pols_in])
fc_write_parts(fc_file, verts, pols, node.part_name, None, node.obj_format)
elif node.obj_format == 'solid':
if node.inputs['Solid'].is_linked:
solid=node.inputs['Solid'].sv_get()
fc_write_parts(fc_file, None, None, node.part_name, solid, node.obj_format)
else:
return
def process(self):
if self.write_update:
self.write_FCStd(self)
else:
return
def fc_write_parts(fc_file, verts, faces, part_name, solid, mod):
try:
F.open(fc_file)
Fname = bpy.path.display_name_from_filepath(fc_file)
except:
info ('FCStd open error')
return
F.setActiveDocument(Fname)
fc_root = F.getDocument(Fname)
obj_names = set( [ i.Name for i in fc_root.Objects] )
part_name += '_sv_' #->suffix added to avoid deleting erroneusly freecad objects
# SEARCH the freecad project for previous writed parts from this node
if part_name in obj_names: #if the part name is numberless is detected as single
fc_root.removeObject(part_name)
else:
for name in obj_names: #if not, check the fc project if there are parts with same root name
if part_name in name:
fc_root.removeObject(name)
############### if there, previous writed parts are removed ####################
############### so then write them again...
if mod == 'solid': #EXPORT SOLID
for i,s in enumerate(solid):
new_part = F.ActiveDocument.addObject( "Part::Feature",part_name+str(i) ) #multiple: give numbered name
new_part.Shape = s
else: #EXPORT MESH
import Mesh
for i in range(len(verts)):
temp_faces=faces[i]
temp_verts=verts[i]
meshdata=[]
for f in temp_faces:
v1,v2,v3 = f[0],f[1],f[2]
meshdata.append( temp_verts[v1] )
meshdata.append( temp_verts[v2] )
meshdata.append( temp_verts[v3] )
mesh = Mesh.Mesh( meshdata )
obj = F.ActiveDocument.addObject( "Mesh::Feature", part_name+str(i) )
obj.Mesh = mesh
F.ActiveDocument.recompute()
F.getDocument(Fname).save()
F.closeDocument(Fname)
def register():
if FreeCAD is not None:
bpy.utils.register_class(SvWriteFCStdNode)
bpy.utils.register_class(SvWriteFCStdOperator)
def unregister():
if FreeCAD is not None:
bpy.utils.unregister_class(SvWriteFCStdNode)
bpy.utils.unregister_class(SvWriteFCStdOperator)
import bpy,bmesh
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 bpy.props import StringProperty, BoolProperty, EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.logging import info
class SvApproxSubdtoNurbsOperator(bpy.types.Operator, SvGenericNodeLocator):
bl_idname = "node.approx_subd_nurbs_operator"
bl_label = "Approx Subd-Nurbs"
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'}
try:
node.inputs['Subd Obj'].sv_get()[0]
except:
return {'CANCELLED'}
node.Approximate(node)
updateNode(node,context)
return {'FINISHED'}
class SvApproxSubdtoNurbsNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Approximate Subd to Nurbs
Tooltip: Approximate Subd to Nurbs
"""
bl_idname = 'SvApproxSubdtoNurbsNode'
bl_label = 'Approximate Subd to Nurb'
bl_icon = 'IMPORT'
solid_catergory = "Outputs"
auto_update : BoolProperty(name="auto_update", default=True)
def draw_buttons(self, context, layout):
col = layout.column(align=True)
col.prop(self, 'auto_update', text = 'global update')
self.wrapper_tracked_ui_draw_op(layout, SvApproxSubdtoNurbsOperator.bl_idname, icon='FILE_REFRESH', text="UPDATE")
def sv_init(self, context):
self.inputs.new('SvObjectSocket', "Subd Obj")
self.outputs.new('SvSolidSocket', "Solid")
def Approximate(self,node):
S = ApproxSubdToNurbs( node.inputs['Subd Obj'].sv_get()[0] )
node.outputs['Solid'].sv_set(S)
def process(self):
if not any(socket.is_linked for socket in self.outputs):
return
try:
self.inputs['Subd Obj'].sv_get()[0]
except:
return
if self.auto_update:
self.Approximate(self)
else:
return
def ApproxSubdToNurbs(Object):
from FreeCAD import Part
from FreeCAD.Part import BSplineCurve
from FreeCAD.Part import makeCompound
F.newDocument("freecad_temp")
F.setActiveDocument('freecad_temp')
patches=[]
obj = Object
if obj.modifiers[0].levels <= 1:
return []
else:
obj.modifiers[0].levels -= 1
obj.modifiers[0].subdivision_type = "SIMPLE"
depsgraph = bpy.context.evaluated_depsgraph_get()
obj = obj.evaluated_get(depsgraph)
bm = bmesh.new()
bm.from_mesh(obj.data)
face_corners = set()
for f in bm.faces:
corners = []
for l in f.loops:
pos = (l.vert.co.x,l.vert.co.y,l.vert.co.z)
corners.append( pos )
face_corners.add(tuple(corners))
bm.free()
obj = Object
obj.modifiers[0].levels += 1
depsgraph = bpy.context.evaluated_depsgraph_get()
obj = obj.evaluated_get(depsgraph)
bm = bmesh.new()
bm.from_mesh(obj.data)
borders=[]
centers=[]
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
for quad_co in face_corners:
quad = []
for co in quad_co:
for v in bm.verts:
if (v.co.x,v.co.y,v.co.z) == co: quad.append(v.index)
edges = []
for i in range(4):
j = 0 if i == 3 else i+1
for vert in bm.verts:
pool = set()
for e in vert.link_edges:
for v in e.verts:
pool.add(v.index)
edge = set((quad[i],quad[j]))
if edge.issubset(pool):
edge = ( quad[i], vert.index, quad[j] )
edges.append( edge )
set1 = set()
for e in bm.verts[edges[0][1]].link_edges:
for v in e.verts:
set1.add(v.index)
set2 = set()
for e in bm.verts[edges[1][1]].link_edges:
for v in e.verts:
set2.add(v.index)
borders.append(edges)
centers.append( ((set1&set2)-set(quad)).pop() )
obj = Object
obj.modifiers[0].subdivision_type = "CATMULL_CLARK"
depsgraph = bpy.context.evaluated_depsgraph_get()
obj = obj.evaluated_get(depsgraph)
bm = bmesh.new()
bm.from_mesh(obj.data)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
v_borders=[]
v_centers=[]
for p in centers:
p = bm.verts[p]
v_centers.append( (p.co.x,p.co.y,p.co.z) )
for b in borders:
border=[]
for e in b:
edges=[]
for p in e:
p = bm.verts[p]
edges.append( (p.co.x,p.co.y,p.co.z) )
border.append( edges )
v_borders.append(border)
bm.free()
for i in range(len(centers)):
p = v_borders[i]
cen = v_centers[i]
curves=[]
item=0
CEN = F.ActiveDocument.addObject('Part::Feature', 'boundary_center%s'%item)
CEN.Shape = Part.Point( F.Vector( cen ) ).toShape()
for b in p:
Points=[]
Points.append( F.Vector( b[0]) )
Points.append( F.Vector( b[1]) )
Points.append( F.Vector( b[2]) )
curve = BSplineCurve()
curve.increaseDegree(1)
curve.interpolate(Points)
curves.append(curve)
com = makeCompound([x.toShape() for x in curves])
com_obj = F.ActiveDocument.addObject('Part::Feature', 'boundary_edges%s'%item)
com_obj.Shape = com
F.ActiveDocument.recompute()
edge_names = ["Edge%d"%(n+1) for n in range(len(com.Edges))]
patch = F.ActiveDocument.addObject("Surface::Filling","Surface%s"%item)
patch.BoundaryEdges = (com_obj, edge_names)
patch.Points = (CEN, "Vertex1")
F.ActiveDocument.recompute()
item+=1
F.ActiveDocument.recompute()
SURFS= []
for obj in F.ActiveDocument.Objects:
if 'Surface' in obj.Name:
SURFS.append(obj)
F.activeDocument().addObject("Part::Compound","Compound")
COMPOUND = F.ActiveDocument.getObject("Compound")
COMPOUND.Links = SURFS
F.ActiveDocument.recompute()
COMPOUND.recompute()
SHELL = Part.Solid( Part.Shell(COMPOUND.Shape.Faces) )
F.closeDocument("freecad_temp")
return [SHELL]
def register():
if FreeCAD is not None:
bpy.utils.register_class(SvApproxSubdtoNurbsOperator)
bpy.utils.register_class(SvApproxSubdtoNurbsNode)
def unregister():
if FreeCAD is not None:
bpy.utils.unregister_class(SvApproxSubdtoNurbsOperator)
bpy.utils.unregister_class(SvApproxSubdtoNurbsNode)
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать