TclCommandPanelize.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. from ObjectCollection import *
  2. from copy import copy,deepcopy
  3. from tclCommands.TclCommand import TclCommand
  4. class TclCommandPanelize(TclCommand):
  5. """
  6. Tcl shell command to panelize an object.
  7. example:
  8. """
  9. # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
  10. aliases = ['panelize','pan', 'panel']
  11. # Dictionary of types from Tcl command, needs to be ordered
  12. arg_names = collections.OrderedDict([
  13. ('name', str),
  14. ])
  15. # Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
  16. option_types = collections.OrderedDict([
  17. ('rows', int),
  18. ('columns', int),
  19. ('spacing_columns', float),
  20. ('spacing_rows', float),
  21. ('box', str),
  22. ('outname', str),
  23. ('threaded', int)
  24. ])
  25. # array of mandatory options for current Tcl command: required = {'name','outname'}
  26. required = ['name', 'rows', 'columns']
  27. # structured help for current command, args needs to be ordered
  28. help = {
  29. 'main': 'Rectangular panelizing.',
  30. 'args': collections.OrderedDict([
  31. ('name', 'Name of the object to panelize.'),
  32. ('box', 'Name of object which acts as box (cutout for example.)'
  33. 'for cutout boundary. Object from name is used if not specified.'),
  34. ('spacing_columns', 'Spacing between columns.'),
  35. ('spacing_rows', 'Spacing between rows.'),
  36. ('columns', 'Number of columns.'),
  37. ('rows', 'Number of rows;'),
  38. ('outname', 'Name of the new geometry object.'),
  39. ('threaded', '0 = non-threaded || 1 = threaded')
  40. ]),
  41. 'examples': []
  42. }
  43. def execute(self, args, unnamed_args):
  44. """
  45. :param args:
  46. :param unnamed_args:
  47. :return:
  48. """
  49. name = args['name']
  50. # Get source object.
  51. try:
  52. obj = self.app.collection.get_by_name(str(name))
  53. except:
  54. return "Could not retrieve object: %s" % name
  55. if obj is None:
  56. return "Object not found: %s" % name
  57. if 'box' in args:
  58. boxname = args['box']
  59. try:
  60. box = self.app.collection.get_by_name(boxname)
  61. except:
  62. return "Could not retrieve object: %s" % name
  63. else:
  64. box = obj
  65. if 'columns' not in args or 'rows' not in args:
  66. return "ERROR: Specify -columns and -rows"
  67. if 'outname' in args:
  68. outname = args['outname']
  69. else:
  70. outname = name + '_panelized'
  71. if 'threaded' in args:
  72. threaded = args['threaded']
  73. else:
  74. threaded = 0
  75. if 'spacing_columns' in args:
  76. spacing_columns = args['spacing_columns']
  77. else:
  78. spacing_columns = 5
  79. if 'spacing_rows' in args:
  80. spacing_rows = args['spacing_rows']
  81. else:
  82. spacing_rows = 5
  83. rows = args['rows']
  84. columns = args['columns']
  85. xmin, ymin, xmax, ymax = box.bounds()
  86. lenghtx = xmax - xmin + spacing_columns
  87. lenghty = ymax - ymin + spacing_rows
  88. # def panelize():
  89. # currenty = 0
  90. #
  91. # def initialize_local(obj_init, app):
  92. # obj_init.solid_geometry = obj.solid_geometry
  93. # obj_init.offset([float(currentx), float(currenty)])
  94. # objs.append(obj_init)
  95. #
  96. # def initialize_local_excellon(obj_init, app):
  97. # obj_init.tools = obj.tools
  98. # # drills are offset, so they need to be deep copied
  99. # obj_init.drills = deepcopy(obj.drills)
  100. # obj_init.offset([float(currentx), float(currenty)])
  101. # obj_init.create_geometry()
  102. # objs.append(obj_init)
  103. #
  104. # def initialize_geometry(obj_init, app):
  105. # FlatCAMGeometry.merge(objs, obj_init)
  106. #
  107. # def initialize_excellon(obj_init, app):
  108. # # merge expects tools to exist in the target object
  109. # obj_init.tools = obj.tools.copy()
  110. # FlatCAMExcellon.merge(objs, obj_init)
  111. #
  112. # objs = []
  113. # if obj is not None:
  114. #
  115. # for row in range(rows):
  116. # currentx = 0
  117. # for col in range(columns):
  118. # local_outname = outname + ".tmp." + str(col) + "." + str(row)
  119. # if isinstance(obj, FlatCAMExcellon):
  120. # self.app.new_object("excellon", local_outname, initialize_local_excellon, plot=False,
  121. # autoselected=False)
  122. # else:
  123. # self.app.new_object("geometry", local_outname, initialize_local, plot=False,
  124. # autoselected=False)
  125. #
  126. # currentx += lenghtx
  127. # currenty += lenghty
  128. #
  129. # if isinstance(obj, FlatCAMExcellon):
  130. # self.app.new_object("excellon", outname, initialize_excellon)
  131. # else:
  132. # self.app.new_object("geometry", outname, initialize_geometry)
  133. #
  134. # # deselect all to avoid delete selected object when run delete from shell
  135. # self.app.collection.set_all_inactive()
  136. # for delobj in objs:
  137. # self.app.collection.set_active(delobj.options['name'])
  138. # self.app.on_delete()
  139. # else:
  140. # return "fail"
  141. #
  142. # ret_value = panelize()
  143. # if ret_value == 'fail':
  144. # return 'fail'
  145. def panelize_2():
  146. if obj is not None:
  147. self.app.inform.emit("Generating panel ... Please wait.")
  148. self.app.progress.emit(0)
  149. def job_init_excellon(obj_fin, app_obj):
  150. currenty = 0.0
  151. self.app.progress.emit(10)
  152. obj_fin.tools = obj.tools.copy()
  153. obj_fin.drills = []
  154. obj_fin.slots = []
  155. obj_fin.solid_geometry = []
  156. for option in obj.options:
  157. if option is not 'name':
  158. try:
  159. obj_fin.options[option] = obj.options[option]
  160. except:
  161. log.warning("Failed to copy option.", option)
  162. for row in range(rows):
  163. currentx = 0.0
  164. for col in range(columns):
  165. if obj.drills:
  166. for tool_dict in obj.drills:
  167. point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
  168. obj_fin.drills.append(
  169. {
  170. "point": point_offseted,
  171. "tool": tool_dict['tool']
  172. }
  173. )
  174. if obj.slots:
  175. for tool_dict in obj.slots:
  176. start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
  177. stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
  178. obj_fin.slots.append(
  179. {
  180. "start": start_offseted,
  181. "stop": stop_offseted,
  182. "tool": tool_dict['tool']
  183. }
  184. )
  185. currentx += lenghtx
  186. currenty += lenghty
  187. obj_fin.create_geometry()
  188. obj_fin.zeros = obj.zeros
  189. obj_fin.units = obj.units
  190. def job_init_geometry(obj_fin, app_obj):
  191. currentx = 0.0
  192. currenty = 0.0
  193. def translate_recursion(geom):
  194. if type(geom) == list:
  195. geoms = list()
  196. for local_geom in geom:
  197. geoms.append(translate_recursion(local_geom))
  198. return geoms
  199. else:
  200. return affinity.translate(geom, xoff=currentx, yoff=currenty)
  201. obj_fin.solid_geometry = []
  202. if isinstance(obj, FlatCAMGeometry):
  203. obj_fin.multigeo = obj.multigeo
  204. obj_fin.tools = deepcopy(obj.tools)
  205. if obj.multigeo is True:
  206. for tool in obj.tools:
  207. obj_fin.tools[tool]['solid_geometry'][:] = []
  208. self.app.progress.emit(0)
  209. for row in range(rows):
  210. currentx = 0.0
  211. for col in range(columns):
  212. if isinstance(obj, FlatCAMGeometry):
  213. if obj.multigeo is True:
  214. for tool in obj.tools:
  215. obj_fin.tools[tool]['solid_geometry'].append(translate_recursion(
  216. obj.tools[tool]['solid_geometry'])
  217. )
  218. else:
  219. obj_fin.solid_geometry.append(
  220. translate_recursion(obj.solid_geometry)
  221. )
  222. else:
  223. obj_fin.solid_geometry.append(
  224. translate_recursion(obj.solid_geometry)
  225. )
  226. currentx += lenghtx
  227. currenty += lenghty
  228. if isinstance(obj, FlatCAMExcellon):
  229. self.app.progress.emit(50)
  230. self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
  231. else:
  232. self.app.progress.emit(50)
  233. self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
  234. if threaded == 1:
  235. proc = self.app.proc_container.new("Generating panel ... Please wait.")
  236. def job_thread(app_obj):
  237. try:
  238. panelize_2()
  239. self.app.inform.emit("[success] Panel created successfully.")
  240. except Exception as e:
  241. proc.done()
  242. log.debug(str(e))
  243. return
  244. proc.done()
  245. self.app.collection.promise(outname)
  246. self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
  247. else:
  248. panelize_2()
  249. self.app.inform.emit("[success] Panel created successfully.")