1import os 2import logging 3import platform 4import subprocess 5 6from string import Template 7from tempfile import NamedTemporaryFile 8from subprocess import check_call 9 10from .. import exchange 11 12# create a default logger 13log = logging.getLogger('trimesh.interfaces') 14 15 16class MeshScript: 17 18 def __init__(self, 19 meshes, 20 script, 21 tmpfile_ext='stl', 22 debug=False, 23 **kwargs): 24 25 self.debug = debug 26 self.kwargs = kwargs 27 self.meshes = meshes 28 self.script = script 29 self.tmpfile_ext = tmpfile_ext 30 31 def __enter__(self): 32 # windows has problems with multiple programs using open files so we close 33 # them at the end of the enter call, and delete them ourselves at the 34 # exit 35 self.mesh_pre = [ 36 NamedTemporaryFile( 37 suffix='.{}'.format( 38 self.tmpfile_ext), 39 mode='wb', 40 delete=False) for i in self.meshes] 41 self.mesh_post = NamedTemporaryFile( 42 suffix='.{}'.format( 43 self.tmpfile_ext), 44 mode='rb', 45 delete=False) 46 self.script_out = NamedTemporaryFile(mode='wb', 47 delete=False) 48 49 # export the meshes to a temporary STL container 50 for mesh, file_obj in zip(self.meshes, self.mesh_pre): 51 mesh.export(file_obj.name) 52 53 self.replacement = {'MESH_' + str(i): m.name 54 for i, m in enumerate(self.mesh_pre)} 55 self.replacement['MESH_PRE'] = str( 56 [i.name for i in self.mesh_pre]) 57 self.replacement['MESH_POST'] = self.mesh_post.name 58 self.replacement['SCRIPT'] = self.script_out.name 59 60 script_text = Template(self.script).substitute(self.replacement) 61 if platform.system() == 'Windows': 62 script_text = script_text.replace('\\', '\\\\') 63 64 self.script_out.write(script_text.encode('utf-8')) 65 66 # close all temporary files 67 self.script_out.close() 68 self.mesh_post.close() 69 for file_obj in self.mesh_pre: 70 file_obj.close() 71 return self 72 73 def run(self, command): 74 command_run = Template(command).substitute( 75 self.replacement).split() 76 # run the binary 77 # avoid resourcewarnings with null 78 with open(os.devnull, 'w') as devnull: 79 startupinfo = None 80 if platform.system() == 'Windows': 81 startupinfo = subprocess.STARTUPINFO() 82 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 83 if self.debug: 84 # in debug mode print the output 85 stdout = None 86 else: 87 stdout = devnull 88 89 if self.debug: 90 log.info('executing: {}'.format(' '.join(command_run))) 91 check_call(command_run, 92 stdout=stdout, 93 stderr=subprocess.STDOUT, 94 startupinfo=startupinfo) 95 96 # bring the binaries result back as a set of Trimesh kwargs 97 mesh_results = exchange.load.load_mesh(self.mesh_post.name, 98 **self.kwargs) 99 100 return mesh_results 101 102 def __exit__(self, *args, **kwargs): 103 if self.debug: 104 print('MeshScript.debug: not deleting {}'.format( 105 self.script_out.name)) 106 return 107 # delete all the temporary files by name 108 # they are closed but their names are still available 109 os.remove(self.script_out.name) 110 for file_obj in self.mesh_pre: 111 os.remove(file_obj.name) 112 os.remove(self.mesh_post.name) 113