TclCommandPaint.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from ObjectCollection import *
  2. from tclCommands.TclCommand import TclCommand
  3. import gettext
  4. import FlatCAMTranslation as fcTranslate
  5. import builtins
  6. fcTranslate.apply_language('strings')
  7. if '_' not in builtins.__dict__:
  8. _ = gettext.gettext
  9. class TclCommandPaint(TclCommand):
  10. """
  11. Paint the interior of polygons
  12. """
  13. # Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
  14. aliases = ['paint']
  15. # dictionary of types from Tcl command, needs to be ordered
  16. arg_names = collections.OrderedDict([
  17. ('name', str),
  18. ])
  19. # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
  20. option_types = collections.OrderedDict([
  21. ('tooldia', str),
  22. ('overlap', float),
  23. ('order', str),
  24. ('margin', float),
  25. ('method', str),
  26. ('connect', bool),
  27. ('contour', bool),
  28. ('all', bool),
  29. ('single', bool),
  30. ('ref', bool),
  31. ('box', str),
  32. ('x', float),
  33. ('y', float),
  34. ('outname', str),
  35. ])
  36. # array of mandatory options for current Tcl command: required = {'name','outname'}
  37. required = ['name']
  38. # structured help for current command, args needs to be ordered
  39. help = {
  40. 'main': "Paint polygons",
  41. 'args': collections.OrderedDict([
  42. ('name', 'Name of the source Geometry object. String.'),
  43. ('tooldia', 'Diameter of the tool to be used. Can be a comma separated list of diameters. No space is '
  44. 'allowed between tool diameters. E.g: correct: 0.5,1 / incorrect: 0.5, 1'),
  45. ('overlap', 'Fraction of the tool diameter to overlap cuts. Float number.'),
  46. ('margin', 'Bounding box margin. Float number.'),
  47. ('order', 'Can have the values: "no", "fwd" and "rev". String.'
  48. 'It is useful when there are multiple tools in tooldia parameter.'
  49. '"no" -> the order used is the one provided.'
  50. '"fwd" -> tools are ordered from smallest to biggest.'
  51. '"rev" -> tools are ordered from biggest to smallest.'),
  52. ('method', 'Algorithm for painting. Can be: "standard", "seed" or "lines".'),
  53. ('connect', 'Draw lines to minimize tool lifts. True or False'),
  54. ('contour', 'Cut around the perimeter of the painting. True or False'),
  55. ('all', 'Paint all polygons in the object. True or False'),
  56. ('single', 'Paint a single polygon specified by "x" and "y" parameters. True or False'),
  57. ('ref', 'Paint all polygons within a specified object with the name in "box" parameter. True or False'),
  58. ('box', 'name of the object to be used as paint reference when selecting "ref"" True. String.'),
  59. ('x', 'X value of coordinate for the selection of a single polygon. Float number.'),
  60. ('y', 'Y value of coordinate for the selection of a single polygon. Float number.'),
  61. ('outname', 'Name of the resulting Geometry object. String.'),
  62. ]),
  63. 'examples': []
  64. }
  65. def execute(self, args, unnamed_args):
  66. """
  67. execute current TCL shell command
  68. :param args: array of known named arguments and options
  69. :param unnamed_args: array of other values which were passed into command
  70. without -somename and we do not have them in known arg_names
  71. :return: None or exception
  72. """
  73. name = args['name']
  74. if 'tooldia' in args:
  75. tooldia = str(args['tooldia'])
  76. else:
  77. tooldia = float(self.app.defaults["tools_paintoverlap"])
  78. if 'overlap' in args:
  79. overlap = float(args['overlap'])
  80. else:
  81. overlap = float(self.app.defaults["tools_paintoverlap"])
  82. if 'order' in args:
  83. order = args['order']
  84. else:
  85. order = str(self.app.defaults["tools_paintorder"])
  86. if 'margin' in args:
  87. margin = float(args['margin'])
  88. else:
  89. margin = float(self.app.defaults["tools_paintmargin"])
  90. if 'method' in args:
  91. method = args['method']
  92. else:
  93. method = str(self.app.defaults["tools_paintmethod"])
  94. if 'connect' in args:
  95. connect = eval(str(args['connect']).capitalize())
  96. else:
  97. connect = eval(str(self.app.defaults["tools_pathconnect"]))
  98. if 'contour' in args:
  99. contour = eval(str(args['contour']).capitalize())
  100. else:
  101. contour = eval(str(self.app.defaults["tools_paintcontour"]))
  102. if 'outname' in args:
  103. outname = args['outname']
  104. else:
  105. outname = name + "_paint"
  106. # Get source object.
  107. try:
  108. obj = self.app.collection.get_by_name(str(name))
  109. except Exception as e:
  110. log.debug("TclCommandPaint.execute() --> %s" % str(e))
  111. self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
  112. return "Could not retrieve object: %s" % name
  113. try:
  114. tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
  115. except AttributeError:
  116. tools = [float(tooldia)]
  117. # store here the default data for Geometry Data
  118. default_data = {}
  119. default_data.update({
  120. "name": '_paint',
  121. "plot": self.app.defaults["geometry_plot"],
  122. "cutz": self.app.defaults["geometry_cutz"],
  123. "vtipdia": 0.1,
  124. "vtipangle": 30,
  125. "travelz": self.app.defaults["geometry_travelz"],
  126. "feedrate": self.app.defaults["geometry_feedrate"],
  127. "feedrate_z": self.app.defaults["geometry_feedrate_z"],
  128. "feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
  129. "dwell": self.app.defaults["geometry_dwell"],
  130. "dwelltime": self.app.defaults["geometry_dwelltime"],
  131. "multidepth": self.app.defaults["geometry_multidepth"],
  132. "ppname_g": self.app.defaults["geometry_ppname_g"],
  133. "depthperpass": self.app.defaults["geometry_depthperpass"],
  134. "extracut": self.app.defaults["geometry_extracut"],
  135. "toolchange": self.app.defaults["geometry_toolchange"],
  136. "toolchangez": self.app.defaults["geometry_toolchangez"],
  137. "endz": self.app.defaults["geometry_endz"],
  138. "spindlespeed": self.app.defaults["geometry_spindlespeed"],
  139. "toolchangexy": self.app.defaults["geometry_toolchangexy"],
  140. "startz": self.app.defaults["geometry_startz"],
  141. "tooldia": self.app.defaults["tools_painttooldia"],
  142. "paintmargin": self.app.defaults["tools_paintmargin"],
  143. "paintmethod": self.app.defaults["tools_paintmethod"],
  144. "selectmethod": self.app.defaults["tools_selectmethod"],
  145. "pathconnect": self.app.defaults["tools_pathconnect"],
  146. "paintcontour": self.app.defaults["tools_paintcontour"],
  147. "paintoverlap": self.app.defaults["tools_paintoverlap"]
  148. })
  149. paint_tools = dict()
  150. tooluid = 0
  151. for tool in tools:
  152. tooluid += 1
  153. paint_tools.update({
  154. int(tooluid): {
  155. 'tooldia': float('%.4f' % tool),
  156. 'offset': 'Path',
  157. 'offset_value': 0.0,
  158. 'type': 'Iso',
  159. 'tool_type': 'C1',
  160. 'data': dict(default_data),
  161. 'solid_geometry': []
  162. }
  163. })
  164. if obj is None:
  165. return "Object not found: %s" % name
  166. # Paint all polygons in the painted object
  167. if 'all' in args and args['all'] is True:
  168. self.app.paint_tool.paint_poly_all(obj=obj,
  169. tooldia=tooldia,
  170. overlap=overlap,
  171. order=order,
  172. margin=margin,
  173. method=method,
  174. outname=outname,
  175. connect=connect,
  176. contour=contour,
  177. tools_storage=paint_tools,
  178. plot=False,
  179. run_threaded=False)
  180. return
  181. # Paint single polygon in the painted object
  182. elif 'single' in args and args['single'] is True:
  183. if 'x' not in args or 'y' not in args:
  184. self.raise_tcl_error('%s' % _("Expected -x <value> and -y <value>."))
  185. else:
  186. x = args['x']
  187. y = args['y']
  188. self.app.paint_tool.paint_poly(obj=obj,
  189. inside_pt=[x, y],
  190. tooldia=tooldia,
  191. overlap=overlap,
  192. order=order,
  193. margin=margin,
  194. method=method,
  195. outname=outname,
  196. connect=connect,
  197. contour=contour,
  198. tools_storage=paint_tools,
  199. plot=False,
  200. run_threaded=False)
  201. return
  202. # Paint all polygons found within the box object from the the painted object
  203. elif 'ref' in args and args['ref'] is True:
  204. if 'box' not in args:
  205. self.raise_tcl_error('%s' % _("Expected -box <value>."))
  206. else:
  207. box_name = args['box']
  208. # Get box source object.
  209. try:
  210. box_obj = self.app.collection.get_by_name(str(box_name))
  211. except Exception as e:
  212. log.debug("TclCommandPaint.execute() --> %s" % str(e))
  213. self.raise_tcl_error("%s: %s" % (_("Could not retrieve box object"), name))
  214. return "Could not retrieve object: %s" % name
  215. self.app.paint_tool.paint_poly_ref(obj=obj,
  216. sel_obj=box_obj,
  217. tooldia=tooldia,
  218. overlap=overlap,
  219. order=order,
  220. margin=margin,
  221. method=method,
  222. outname=outname,
  223. connect=connect,
  224. contour=contour,
  225. tools_storage=paint_tools,
  226. plot=False,
  227. run_threaded=False)
  228. return
  229. else:
  230. self.raise_tcl_error("%s:" % _("There was none of the following args: 'ref', 'single', 'all'.\n"
  231. "Paint failed."))
  232. return "There was none of the following args: 'ref', 'single', 'all'.\n" \
  233. "Paint failed."