FreeCAD-macros
114 строк · 3.7 Кб
1# -*- coding: utf-8 -*-
2# Opens current visible objects in Slic3r. One can use different slicing software
3
4__Title__ = '3D Print / Slice'
5__Author__ = 'Damian Łoziński'
6__Version__ = '0.4.1'
7__Date__ = '2024-08-28'
8__Comment__ = 'Export selected objects to amf/stl files and open them in slicing program'
9__Web__ = 'https://github.com/dlozinski/FreeCAD-macros/blob/doc/ImportExport/ExportToSlicer.md'
10__Wiki__ = ''
11__Icon__ = 'Export2Slicer.png'
12__Help__ = 'You may need to change slicer path. To do so open Tools > Edit parameters > BaseApp/Preferences/Macros/Export2Slicer'
13__Status__ = 'Stable'
14__Requires__ = 'freecad 0.17+'
15__Communication__ = 'lozinski dot d at gmail dot com'
16__Files__ = 'Export2Slicer.png'
17
18import os
19import re
20from subprocess import Popen
21import shlex
22
23import FreeCAD as app
24import FreeCADGui as gui
25import Mesh
26import MeshPart
27
28
29MACRO_PARAMS = app.ParamGet('User parameter:BaseApp/Preferences/Macros/Export2Slicer')
30DEFAULT_SLICER_CMD = '"/Applications/Original Prusa Drivers/PrusaSlicer.app/Contents/MacOS/PrusaSlicer" --single-instance "{file}"'
31DEFAULT_OUTPUT_FORMAT = 'amf'
32DEFAULT_ANGULAR_DEFLECTION = 0.07
33
34
35def get_string_param(name, default):
36value = MACRO_PARAMS.GetString(name)
37if not value:
38MACRO_PARAMS.SetString(name, default)
39value = default
40return value
41
42
43def get_float_param(name, default):
44value = MACRO_PARAMS.GetFloat(name)
45if not value:
46MACRO_PARAMS.SetFloat(name, default)
47value = default
48return value
49
50
51slicer_cmd = get_string_param('SlicerCommand', DEFAULT_SLICER_CMD)
52output_format = get_string_param('OutputFormat', DEFAULT_OUTPUT_FORMAT)
53angular_deflection = get_float_param('AngularDeflection', DEFAULT_ANGULAR_DEFLECTION)
54
55
56def escape(text):
57return re.sub(r'\W', '_', text)
58
59
60def get_mesh_filename(doc_filename, mesh_names):
61"""Returns valid filename for temporary mesh file."""
62if doc_filename:
63dirname = os.path.dirname(doc_filename)
64filename = (
65os.path.basename(doc_filename).partition('.')[0]
66+ '-'
67+ escape('_'.join(mesh_names))
68+ '.'
69+ output_format)
70file_path = os.path.join(dirname, filename)
71else:
72file_path = 'meshes-export.' + output_format
73return file_path
74
75
76def main():
77doc = app.activeDocument()
78if not doc:
79raise RuntimeError('Export2Slicer: No active document')
80
81selection = gui.Selection.getSelectionEx()
82objects_to_export = [x.Object for x in selection] or [doc.ActiveObject]
83try:
84# Create temporary doc to store meshes so that we don't affect current doc history
85tmp_doc = app.newDocument('meshes_to_export', temp=True)
86meshes = []
87mesh_names = []
88for o in objects_to_export:
89if o.TypeId == 'Mesh::Feature':
90meshes.append(o)
91else:
92mesh = tmp_doc.addObject('Mesh::Feature', f'{doc.Label}_{o.Label}')
93mesh.Mesh = MeshPart.meshFromShape(o.Shape, LinearDeflection=0.1, AngularDeflection=angular_deflection, Relative=False)
94meshes.append(mesh)
95mesh_names.append(o.Label)
96if meshes:
97mesh_path = get_mesh_filename(doc.FileName, mesh_names)
98Mesh.export(meshes, mesh_path)
99else:
100raise RuntimeError('Export2Slicer: No objects to export')
101finally:
102app.closeDocument('meshes_to_export')
103for x in selection:
104gui.Selection.addSelection(doc.Name, x.ObjectName)
105
106# Launch Slicer with meshes
107Popen(shlex.split(slicer_cmd.format(file=mesh_path)))
108app.Console.PrintMessage(f'Export2Slicer: Objects exported into: {mesh_path}\n')
109
110
111try:
112main()
113except Exception as e:
114app.Console.PrintError('Export2Slicer: ERROR: {}\n'.format(e))
115