@@ -138,6 +138,56 @@ def flush(self):
138138
139139log_format = '<level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>'
140140
141+ class RenderWorker (QObject ):
142+ ast_ready = pyqtSignal (str )
143+ python_ready = pyqtSignal (str )
144+ mesh_ready = pyqtSignal (object )
145+ log_message = pyqtSignal (str )
146+ finished = pyqtSignal ()
147+
148+ def __init__ (self , openscad_file ):
149+ super ().__init__ ()
150+ self .openscad_file = openscad_file
151+
152+ @pyqtSlot ()
153+ def run (self ):
154+ try :
155+ #Try and set background threads to a *low* priority,
156+ # since people on the internet seem confused about this
157+ # a higher nice value means your program is *nicer* to
158+ # other programs, and will get out of their way.
159+ try :
160+ os .nice (14 )
161+ except : pass
162+
163+ ast_text = self .openscad_file .as_ast ()
164+ self .ast_ready .emit (ast_text )
165+
166+ python_text = self .openscad_file .as_python ()
167+ self .python_ready .emit (python_text )
168+
169+ result = list (self .openscad_file .run ())
170+ if not result :
171+ self .log_message .emit ("No top level geometry to render" )
172+ else :
173+ res = result [0 ]
174+ if isinstance (res , sdf .SDF2 ):
175+ res = res .extrude (0.1 )
176+
177+ with redirect_stdout (LoggerWriter (logger .opt (depth = 1 ).info )):
178+ points = res .generate ()
179+
180+ points , cells = np .unique (points , axis = 0 , return_inverse = True )
181+ cells = cells .reshape ((- 1 , 3 ))
182+
183+ self .mesh_ready .emit ((points , cells , res ))
184+
185+ except Exception :
186+ logger .exception ("Error during render" )
187+ finally :
188+ self .finished .emit ()
189+
190+
141191class MainUi (QMainWindow ):
142192 def __init__ (self ):
143193 super ().__init__ () # Call the inherited classes __init__ method
@@ -167,6 +217,7 @@ def __init__(self):
167217
168218 self .openscadFile = OpenscadFile ()
169219 self .mesh = None
220+ self .result = None
170221
171222 self .preview3d = gl .GLViewWidget (self .sideSplitter )
172223 self .preview3d .setCameraPosition (distance = 40 )
@@ -228,51 +279,29 @@ def saveFileAs(self):
228279 self .setWindowTitle (f"{ self .openscadFile .file } - pySdfScad" )
229280
230281
231- @logger .catch
232- def _render (self ):
233- try :
234- #Try and set background threads to a *low* priority,
235- # since people on the internet seem confused about this
236- # a higher nice value means your program is *nicer* to
237- # other programs, and will get out of their way.
238- os .nice (14 )
239- except : pass
240-
241- self .openscadFile .text = self .editor .toPlainText ()
242- self .astPreview .setPlainText (self .openscadFile .as_ast ())
243- self .pythonPreview .setPlainText (self .openscadFile .as_python ())
244- result = list (self .openscadFile .run ())
245- if not result :
246- logger .info ("No top level geometry to render" )
247- else :
248- self .result = result [0 ]
249- if isinstance (self .result ,sdf .SDF2 ):
250- self .result = self .result .extrude (0.1 )
251- import numpy as np
252- with redirect_stdout (LoggerWriter (logger .opt (depth = 1 ).info )):
253- points = self .result .generate ()
254- points , cells = np .unique (points , axis = 0 , return_inverse = True )
255- cells = cells .reshape ((- 1 , 3 ))
256- self .mesh = (points ,cells )
257-
258- meshdata = gl .MeshData (vertexes = points , faces = cells )
259- mesh = gl .GLMeshItem (meshdata = meshdata ,
282+ def update_mesh (self , data ):
283+ points , cells , result_obj = data
284+ self .result = result_obj
285+ self .mesh = (points , cells )
286+
287+ meshdata = gl .MeshData (vertexes = points , faces = cells )
288+ mesh = gl .GLMeshItem (meshdata = meshdata ,
260289 smooth = False , drawFaces = True ,
261290 drawEdges = False ,
262291 shader = "normalColor" ,
263292 color = (1 ,1 ,1 ,1 ), edgeColor = (0.2 , 0.5 , 0.2 , 1 )
264293 )
265- self .preview3d .clear ()
266- g = gl .GLGridItem ()
267- g .setSize (200 , 200 )
268- g .setSpacing (10 , 10 )
294+ self .preview3d .clear ()
295+ g = gl .GLGridItem ()
296+ g .setSize (200 , 200 )
297+ g .setSpacing (10 , 10 )
269298
270- a = gl .GLAxisItem ()
271- a .setSize (10 ,10 ,10 )
299+ a = gl .GLAxisItem ()
300+ a .setSize (10 ,10 ,10 )
272301
273- self .preview3d .addItem (g )
274- self .preview3d .addItem (a )
275- self .preview3d .addItem (mesh )
302+ self .preview3d .addItem (g )
303+ self .preview3d .addItem (a )
304+ self .preview3d .addItem (mesh )
276305
277306 def exportMesh (self ):
278307 if not self .result :
@@ -312,8 +341,21 @@ def render(self):
312341 self .preview3d .clear ()
313342 self .astPreview .setPlainText ("" )
314343 self .pythonPreview .setPlainText ("" )
315- thread = Thread (target = self ._render )
316- thread .start ()
344+
345+ self .openscadFile .text = self .editor .toPlainText ()
346+
347+ self .thread = QThread ()
348+ self .worker = RenderWorker (self .openscadFile )
349+ self .worker .moveToThread (self .thread )
350+ self .thread .started .connect (self .worker .run )
351+ self .worker .finished .connect (self .thread .quit )
352+ self .worker .finished .connect (self .worker .deleteLater )
353+ self .thread .finished .connect (self .thread .deleteLater )
354+ self .worker .ast_ready .connect (self .astPreview .setPlainText )
355+ self .worker .python_ready .connect (self .pythonPreview .setPlainText )
356+ self .worker .mesh_ready .connect (self .update_mesh )
357+ self .worker .log_message .connect (logger .info )
358+ self .thread .start ()
317359
318360 def closeEvent (self , event ):
319361 logger .remove (self ._logger_handle_id )
0 commit comments