1
+ #!/usr/bin/env python
2
+ '''
3
+ pyCM fea_widget - runs external thread to run an FEA from a pyCM output file.
4
+ '''
5
+
6
+ __author__ = "M.J. Roy"
7
+ __version__ = "0.1"
8
+
9
+ __status__ = "Experimental"
10
+ __copyright__ = "(c) M. J. Roy, 2014--"
11
+
12
+ import os , io
13
+ import subprocess as sp
14
+ import numpy as np
15
+ import vtk
16
+ import vtk .util .numpy_support as v2n
17
+ from PyQt5 import QtGui , QtWidgets , QtCore
18
+ from PyQt5 .QtCore import Qt , QThread , pyqtSignal
19
+ import yaml
20
+ from d3dslic3r_gui_common import get_file , get_save_file
21
+ import importlib .resources
22
+
23
+ class execute (QThread ):
24
+ '''
25
+ Sets up and runs external thread, emits 100 when done.
26
+ '''
27
+ _signal = pyqtSignal (int )
28
+ def __init__ (self ,input_file ,exe ,val ,direction ):
29
+ super (execute , self ).__init__ ()
30
+ #variables passed here
31
+ self .input_file = input_file
32
+ self .exe = exe #executable path
33
+ self .which_dir = direction
34
+ self .cut_val = val
35
+
36
+ def run (self ):
37
+ current_dir = os .getcwd ()
38
+ output_dir = os .path .dirname (self .input_file )
39
+ base = os .path .basename (self .input_file )
40
+ os .chdir (output_dir )
41
+
42
+ try :
43
+ print ('Slic3r console exec: %s -i %s' % (self .exe ,base ))
44
+
45
+ out = sp .check_output ([self .exe ,"--cut" ,str (self .cut_val ),base ], shell = True )
46
+ print ("Slic3r output log:" )
47
+ print ("----------------" )
48
+ print (out .decode ("utf-8" ))
49
+ print ("----------------" )
50
+ print ("d3dslic3r: Slic3r run completed . . . Idle" )
51
+ except sp .CalledProcessError as e :
52
+ print ("Slic3r command failed for some reason." )
53
+ print (e )
54
+
55
+ self ._signal .emit (100 )
56
+ os .chdir (current_dir )
57
+
58
+
59
+ class slic3r_widget (QtWidgets .QDialog ):
60
+
61
+ def __init__ (self , parent , file ):
62
+ super (slic3r_widget , self ).__init__ (parent )
63
+ self .file = file
64
+
65
+ self .setWindowTitle ("d3dslic3r using Slic3r: %s" % os .path .basename (self .file ))
66
+ self .setWindowFlag (Qt .WindowContextHelpButtonHint , False )
67
+ self .setMinimumSize (QtCore .QSize (450 , 200 ))
68
+
69
+ param_layout = QtWidgets .QGridLayout ()
70
+
71
+ self .cut_x_rb = QtWidgets .QRadioButton ("Cut X" )
72
+ self .cut_x_rb .setEnabled (False )
73
+ self .cut_y_rb = QtWidgets .QRadioButton ("Cut Y" )
74
+ self .cut_y_rb .setEnabled (False )
75
+ self .cut_z_rb = QtWidgets .QRadioButton ("Cut Z" )
76
+ self .cut_val = QtWidgets .QDoubleSpinBox ()
77
+ self .cut_z_rb .setChecked (True )
78
+
79
+ mtype_button_group = QtWidgets .QButtonGroup ()
80
+ mtype_button_group .addButton (self .cut_x_rb )
81
+ mtype_button_group .addButton (self .cut_y_rb )
82
+ mtype_button_group .addButton (self .cut_z_rb )
83
+ mtype_button_group .setExclusive (True )
84
+
85
+ self .clean_up_cb = QtWidgets .QCheckBox ('Remove intermediate files' )
86
+ self .clean_up_cb .setToolTip ('Remove intermediate files after running command' )
87
+ self .clean_up_cb .setChecked (False )
88
+ self .clean_up_cb .setEnabled (False )
89
+
90
+ param_layout .addWidget (self .cut_x_rb ,0 ,0 ,1 ,1 )
91
+ param_layout .addWidget (self .cut_y_rb ,0 ,1 ,1 ,1 )
92
+ param_layout .addWidget (self .cut_z_rb ,0 ,2 ,1 ,1 )
93
+ param_layout .addWidget (self .cut_val ,0 ,3 ,1 ,1 )
94
+ param_layout .addWidget (self .clean_up_cb ,0 ,4 ,1 ,1 )
95
+
96
+ self .pbar = QtWidgets .QProgressBar (self , textVisible = True )
97
+ self .pbar .setAlignment (Qt .AlignCenter )
98
+ self .pbar .setFormat ("Idle" )
99
+ self .pbar .setFont (QtGui .QFont ("Helvetica" ,italic = True ))
100
+ self .pbar .setValue (0 )
101
+
102
+ self .run_button = QtWidgets .QPushButton ('Run' )
103
+ slic3r_exec_path_label = QtWidgets .QLabel ('Slic3r console executable:' )
104
+ self .slic3r_exec_path = QtWidgets .QLineEdit ()
105
+ slic3r_choose_path = QtWidgets .QPushButton ('...' )
106
+ slic3r_choose_path .setMaximumWidth (30 )
107
+ slic3r_choose_path .setAutoDefault (False )
108
+ work_dir_path_label = QtWidgets .QLabel ('Working directory:' )
109
+ self .work_dir_path = QtWidgets .QLineEdit ()
110
+ wd_choose_path = QtWidgets .QPushButton ('...' )
111
+ wd_choose_path .setMaximumWidth (30 )
112
+ wd_choose_path .setAutoDefault (False )
113
+
114
+ run_layout = QtWidgets .QGridLayout ()
115
+
116
+ run_layout .addWidget (slic3r_exec_path_label ,1 ,0 ,1 ,1 )
117
+ run_layout .addWidget (self .slic3r_exec_path ,1 ,1 ,1 ,2 )
118
+ run_layout .addWidget (slic3r_choose_path ,1 ,3 ,1 ,1 )
119
+
120
+ run_layout .addWidget (work_dir_path_label ,2 ,0 ,1 ,1 )
121
+ run_layout .addWidget (self .work_dir_path ,2 ,1 ,1 ,2 )
122
+ run_layout .addWidget (wd_choose_path ,2 ,3 ,1 ,1 )
123
+ run_layout .addWidget (self .run_button ,3 ,0 ,1 ,1 )
124
+ run_layout .addWidget (self .pbar ,3 ,1 ,1 ,3 )
125
+
126
+ self .run_button .clicked .connect (self .run_slic3r )
127
+ slic3r_choose_path .clicked .connect (self .set_slic3r )
128
+ wd_choose_path .clicked .connect (self .set_wd )
129
+
130
+ self .layout = QtWidgets .QVBoxLayout ()
131
+ self .layout .addLayout (param_layout )
132
+ self .layout .addLayout (run_layout )
133
+
134
+ self .setLayout (self .layout )
135
+ self .read_config ()
136
+ self .show ()
137
+
138
+
139
+
140
+ def run_slic3r (self ):
141
+ self .make_config_change () #save anything that the user might have put into config boxes
142
+
143
+ self .input_file = get_file ("*.stl" , self .work_dir_path .text ())
144
+ if self .input_file is None :
145
+ return
146
+
147
+
148
+
149
+ self .thread = execute (self .input_file ,self .slic3r_exec_path .text (), self .cut_val .value (), None ) #None should be direction
150
+
151
+ self .thread ._signal .connect (self .signal_accept )
152
+ self .thread .start ()
153
+ self .pbar .setTextVisible (True )
154
+ self .pbar .setStyleSheet ("" )
155
+ self .pbar .setRange (0 ,0 )
156
+
157
+ def signal_accept (self , msg ):
158
+ if int (msg ) == 100 :
159
+ self .pbar .setRange (0 ,100 )
160
+ self .pbar .setValue (0 )
161
+ self .pbar .setFormat ("Complete" )
162
+ self .pbar .setStyleSheet ("QProgressBar"
163
+ "{"
164
+ "background-color: lightgreen;"
165
+ "border : 1px"
166
+ "}" )
167
+
168
+ def set_slic3r (self ):
169
+ f = get_file ("*.*" )
170
+ if f is None or not (os .path .isfile (f )):
171
+ return
172
+ self .slic3r_exec_path .setText (f )
173
+ self .make_config_change ()
174
+
175
+ def set_wd (self ):
176
+ dir = str (QtWidgets .QFileDialog .getExistingDirectory (self , "Select Directory" ))
177
+ if dir != '' :
178
+ self .work_dir_path .setText (dir )
179
+ self .make_config_change ()
180
+ else :
181
+ return
182
+
183
+ def read_config (self ):
184
+ fname = importlib .resources .files ('d3dslic3r' ) / 'meta/d3dslic3r_config.yml'
185
+ with open (fname , 'r' ) as f :
186
+ read = yaml .safe_load (f )
187
+
188
+ self .slic3r_exec_path .setText (read ['slic3r' ]['exec' ])
189
+ self .work_dir_path .setText (read ['slic3r' ]['work_dir' ])
190
+
191
+
192
+ def make_config_change (self ):
193
+ new_entries = dict (
194
+ slic3r_exec = str (self .slic3r_exec_path .text ()),
195
+ work_dir = str (self .work_dir_path .text ())
196
+ )
197
+
198
+ fname = importlib .resources .files ('d3dslic3r' ) / 'meta/d3dslic3r_config.yml'
199
+ with open (fname , 'r' ) as yamlfile :
200
+ cur_yaml = yaml .safe_load (yamlfile )
201
+ cur_yaml ['slic3r' ].update (new_entries )
202
+ if cur_yaml :
203
+ with open (fname , 'w' ) as yamlfile :
204
+ yaml .safe_dump (cur_yaml , yamlfile )
205
+
206
+ def closeEvent (self , event ):
207
+ '''
208
+ Not implemented
209
+ '''
210
+ pass
211
+
212
+
213
+ if __name__ == "__main__" :
214
+ import sys
215
+ app = QtWidgets .QApplication (sys .argv )
216
+ if len (sys .argv )> 1 :
217
+ fw = slic3r_widget (None , sys .argv [1 ])
218
+ else :
219
+ fw = slic3r_widget (None , 'No file specified' )
220
+ sys .exit (app .exec_ ())
0 commit comments