TclCommandCopperClear.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. from tclCommands.TclCommand import TclCommand
  2. import collections
  3. import logging
  4. import gettext
  5. import appTranslation as fcTranslate
  6. import builtins
  7. fcTranslate.apply_language('strings')
  8. if '_' not in builtins.__dict__:
  9. _ = gettext.gettext
  10. log = logging.getLogger('base')
  11. class TclCommandCopperClear(TclCommand):
  12. """
  13. Clear the non-copper areas.
  14. """
  15. # Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
  16. aliases = ['ncc_clear', 'ncc']
  17. description = '%s %s' % ("--", "Clear excess copper.")
  18. # dictionary of types from Tcl command, needs to be ordered
  19. arg_names = collections.OrderedDict([
  20. ('name', str),
  21. ])
  22. # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
  23. option_types = collections.OrderedDict([
  24. ('tooldia', str),
  25. ('overlap', float),
  26. ('order', str),
  27. ('margin', float),
  28. ('method', str),
  29. ('connect', str),
  30. ('contour', str),
  31. ('offset', float),
  32. ('rest', str),
  33. ('all', int),
  34. ('ref', str),
  35. ('box', str),
  36. ('outname', str),
  37. ])
  38. # array of mandatory options for current Tcl command: required = {'name','outname'}
  39. required = ['name']
  40. # structured help for current command, args needs to be ordered
  41. help = {
  42. 'main': "Clear excess copper in polygons. Basically it's a negative Paint.",
  43. 'args': collections.OrderedDict([
  44. ('name', 'Name of the source Geometry object. String.'),
  45. ('tooldia', 'Diameter of the tool to be used. Can be a comma separated list of diameters.\n'
  46. 'WARNING: No space is allowed between tool diameters. E.g: correct: 0.5,1 / incorrect: 0.5, 1'),
  47. ('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
  48. 'E.g: for a 25% from tool diameter overlap use -overlap 25'),
  49. ('margin', 'Bounding box margin. Float number.'),
  50. ('order', 'Can have the values: "no", "fwd" and "rev". String.'
  51. 'It is useful when there are multiple tools in tooldia parameter.'
  52. '"no" -> the order used is the one provided.'
  53. '"fwd" -> tools are ordered from smallest to biggest.'
  54. '"rev" -> tools are ordered from biggest to smallest.'),
  55. ('method', 'Algorithm for copper clearing. Can be: "standard", "seed" or "lines".'),
  56. ('connect', 'Draw lines to minimize tool lifts. True (1) or False (0)'),
  57. ('contour', 'Cut around the perimeter of the painting. True (1) or False (0)'),
  58. ('rest', 'Use rest-machining. True (1) or False (0)'),
  59. ('offset', 'If used, the copper clearing will finish to a distance from copper features. Float number.'),
  60. ('all', 'If used will copper clear the whole object. Either "-all" or "-box <value>" has to be used.'),
  61. ('box', 'Name of the object to be used as reference. Either "-all" or "-box <value>" has to be used. '
  62. 'String.'),
  63. ('outname', 'Name of the resulting Geometry object. String. No spaces.'),
  64. ]),
  65. 'examples': ["ncc obj_name -tooldia 0.3,1 -overlap 10 -margin 1.0 -method 'lines' -all"]
  66. }
  67. def execute(self, args, unnamed_args):
  68. """
  69. execute current TCL shell command
  70. :param args: array of known named arguments and options
  71. :param unnamed_args: array of other values which were passed into command
  72. without -somename and we do not have them in known arg_names
  73. :return: None or exception
  74. """
  75. name = args['name']
  76. # Get source object.
  77. try:
  78. obj = self.app.collection.get_by_name(str(name))
  79. except Exception as e:
  80. log.debug("TclCommandCopperClear.execute() --> %s" % str(e))
  81. self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
  82. return "Could not retrieve object: %s" % name
  83. if obj is None:
  84. return "Object not found: %s" % name
  85. if 'tooldia' in args:
  86. tooldia = str(args['tooldia'])
  87. else:
  88. tooldia = self.app.defaults["tools_ncc_tools"]
  89. if 'overlap' in args:
  90. overlap = float(args['overlap']) / 100.0
  91. else:
  92. overlap = float(self.app.defaults["tools_ncc_overlap"]) / 100.0
  93. if 'order' in args:
  94. order = args['order']
  95. else:
  96. order = str(self.app.defaults["tools_ncc_order"])
  97. if 'margin' in args:
  98. margin = float(args['margin'])
  99. else:
  100. margin = float(self.app.defaults["tools_ncc_margin"])
  101. if 'method' in args:
  102. method = args['method']
  103. if method == "standard":
  104. method_data = _("Standard")
  105. elif method == "seed":
  106. method_data = _("Seed")
  107. else:
  108. method_data = _("Lines")
  109. else:
  110. method = str(self.app.defaults["tools_ncc_method"])
  111. method_data = method
  112. if method == _("Standard"):
  113. method = "standard"
  114. elif method == _("Seed"):
  115. method = "seed"
  116. else:
  117. method = "lines"
  118. if 'connect' in args:
  119. try:
  120. par = args['connect'].capitalize()
  121. except AttributeError:
  122. par = args['connect']
  123. connect = bool(eval(par))
  124. else:
  125. connect = bool(eval(str(self.app.defaults["tools_ncc_connect"])))
  126. if 'contour' in args:
  127. try:
  128. par = args['contour'].capitalize()
  129. except AttributeError:
  130. par = args['contour']
  131. contour = bool(eval(par))
  132. else:
  133. contour = bool(eval(str(self.app.defaults["tools_ncc_contour"])))
  134. offset = 0.0
  135. if 'offset' in args:
  136. offset = float(args['offset'])
  137. has_offset = True
  138. else:
  139. has_offset = False
  140. try:
  141. tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
  142. except AttributeError:
  143. tools = [float(tooldia)]
  144. if 'rest' in args:
  145. try:
  146. par = args['rest'].capitalize()
  147. except AttributeError:
  148. par = args['rest']
  149. rest = bool(eval(par))
  150. else:
  151. rest = bool(eval(str(self.app.defaults["tools_ncc_rest"])))
  152. if 'outname' in args:
  153. outname = args['outname']
  154. else:
  155. if rest is True:
  156. outname = name + "_ncc"
  157. else:
  158. outname = name + "_ncc_rm"
  159. # used only to have correct information's in the obj.tools[tool]['data'] dict
  160. if "all" in args:
  161. select = _("Itself")
  162. else:
  163. select = _("Reference Object")
  164. # store here the default data for Geometry Data
  165. default_data = {}
  166. default_data.update({
  167. "name": outname,
  168. "plot": False,
  169. "cutz": self.app.defaults["geometry_cutz"],
  170. "vtipdia": float(self.app.defaults["geometry_vtipdia"]),
  171. "vtipangle": float(self.app.defaults["geometry_vtipangle"]),
  172. "travelz": self.app.defaults["geometry_travelz"],
  173. "feedrate": self.app.defaults["geometry_feedrate"],
  174. "feedrate_z": self.app.defaults["geometry_feedrate_z"],
  175. "feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
  176. "dwell": self.app.defaults["geometry_dwell"],
  177. "dwelltime": self.app.defaults["geometry_dwelltime"],
  178. "multidepth": self.app.defaults["geometry_multidepth"],
  179. "ppname_g": self.app.defaults["geometry_ppname_g"],
  180. "depthperpass": self.app.defaults["geometry_depthperpass"],
  181. "extracut": self.app.defaults["geometry_extracut"],
  182. "extracut_length": self.app.defaults["geometry_extracut_length"],
  183. "toolchange": self.app.defaults["geometry_toolchange"],
  184. "toolchangez": self.app.defaults["geometry_toolchangez"],
  185. "endz": self.app.defaults["geometry_endz"],
  186. "endxy": self.app.defaults["geometry_endxy"],
  187. "spindlespeed": self.app.defaults["geometry_spindlespeed"],
  188. "toolchangexy": self.app.defaults["geometry_toolchangexy"],
  189. "startz": self.app.defaults["geometry_startz"],
  190. "area_exclusion": self.app.defaults["geometry_area_exclusion"],
  191. "area_shape": self.app.defaults["geometry_area_shape"],
  192. "area_strategy": self.app.defaults["geometry_area_strategy"],
  193. "area_overz": float(self.app.defaults["geometry_area_overz"]),
  194. "tooldia": self.app.defaults["tools_paint_tooldia"],
  195. "tools_ncc_operation": self.app.defaults["tools_ncc_operation"],
  196. "tools_ncc_margin": margin,
  197. "tools_ncc_method": method_data,
  198. "tools_ncc_ref": select,
  199. "tools_ncc_connect": connect,
  200. "tools_ncc_contour": contour,
  201. "tools_ncc_overlap": overlap,
  202. "tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"],
  203. "tools_ncc_offset_value": self.app.defaults["tools_ncc_offset_value"],
  204. "tools_ncc_milling_type": self.app.defaults["tools_ncc_milling_type"]
  205. })
  206. ncc_tools = {}
  207. tooluid = 0
  208. for tool in tools:
  209. tooluid += 1
  210. ncc_tools.update({
  211. int(tooluid): {
  212. 'tooldia': float('%.*f' % (obj.decimals, tool)),
  213. 'offset': 'Path',
  214. 'offset_value': 0.0,
  215. 'type': 'Iso',
  216. 'tool_type': 'C1',
  217. 'data': dict(default_data),
  218. 'solid_geometry': []
  219. }
  220. })
  221. ncc_tools[int(tooluid)]['data']['tooldia'] = float('%.*f' % (obj.decimals, tool))
  222. # Non-Copper clear all polygons in the non-copper clear object
  223. if 'all' in args:
  224. self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
  225. select_method='itself',
  226. ncctooldia=tooldia,
  227. overlap=overlap,
  228. order=order,
  229. margin=margin,
  230. has_offset=has_offset,
  231. offset=offset,
  232. method=method,
  233. outname=outname,
  234. connect=connect,
  235. contour=contour,
  236. rest=rest,
  237. tools_storage=ncc_tools,
  238. plot=False,
  239. run_threaded=False)
  240. return
  241. # Non-Copper clear all polygons found within the box object from the the non_copper cleared object
  242. if 'box' in args:
  243. box_name = args['box']
  244. # Get box source object.
  245. try:
  246. box_obj = self.app.collection.get_by_name(str(box_name))
  247. except Exception as e:
  248. log.debug("TclCommandCopperClear.execute() --> %s" % str(e))
  249. self.raise_tcl_error("%s: %s" % (_("Could not retrieve box object"), name))
  250. return "Could not retrieve object: %s" % name
  251. self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
  252. sel_obj=box_obj,
  253. select_method='box',
  254. ncctooldia=tooldia,
  255. overlap=overlap,
  256. order=order,
  257. margin=margin,
  258. has_offset=has_offset,
  259. offset=offset,
  260. method=method,
  261. outname=outname,
  262. connect=connect,
  263. contour=contour,
  264. rest=rest,
  265. tools_storage=ncc_tools,
  266. plot=False,
  267. run_threaded=False)
  268. return
  269. # if the program reached this then it's an error because neither -all or -box <value> was used.
  270. self.raise_tcl_error('%s' % _("Expected either -box <value> or -all."))
  271. return "Expected either -box <value> or -all. Copper clearing failed."