ToolCalibrateExcellon.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. # ##########################################################
  2. # FlatCAM: 2D Post-processing for Manufacturing #
  3. # File Author: Marius Adrian Stanciu (c) #
  4. # Date: 3/10/2019 #
  5. # MIT Licence #
  6. # ##########################################################
  7. from PyQt5 import QtWidgets, QtCore
  8. from FlatCAMTool import FlatCAMTool
  9. from flatcamGUI.GUIElements import FCDoubleSpinner, EvalEntry
  10. import math
  11. from shapely.geometry import Point
  12. from shapely.geometry.base import *
  13. import gettext
  14. import FlatCAMTranslation as fcTranslate
  15. import builtins
  16. fcTranslate.apply_language('strings')
  17. if '_' not in builtins.__dict__:
  18. _ = gettext.gettext
  19. class ToolCalibrateExcellon(FlatCAMTool):
  20. toolName = _("Calibrate Excellon")
  21. def __init__(self, app):
  22. FlatCAMTool.__init__(self, app)
  23. self.app = app
  24. self.canvas = self.app.plotcanvas
  25. self.decimals = 4
  26. # ## Title
  27. title_label = QtWidgets.QLabel("%s" % self.toolName)
  28. title_label.setStyleSheet("""
  29. QLabel
  30. {
  31. font-size: 16px;
  32. font-weight: bold;
  33. }
  34. """)
  35. self.layout.addWidget(title_label)
  36. # ## Grid Layout
  37. grid_lay = QtWidgets.QGridLayout()
  38. self.layout.addLayout(grid_lay)
  39. grid_lay.setColumnStretch(0, 0)
  40. grid_lay.setColumnStretch(1, 1)
  41. grid_lay.setColumnStretch(2, 1)
  42. self.exc_object_combo = QtWidgets.QComboBox()
  43. self.exc_object_combo.setModel(self.app.collection)
  44. self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
  45. self.exc_object_combo.setCurrentIndex(1)
  46. self.excobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("EXCELLON"))
  47. self.excobj_label.setToolTip(
  48. _("Excellon Object to be mirrored.")
  49. )
  50. grid_lay.addWidget(self.excobj_label, 0, 0)
  51. grid_lay.addWidget(self.exc_object_combo, 0, 1, 1, 2)
  52. grid_lay.addWidget(QtWidgets.QLabel(''), 1, 0)
  53. self.points_table_label = QtWidgets.QLabel('<b>%s</b>' % _('Calibration Points'))
  54. self.points_table_label.setToolTip(
  55. _("Contain the expected calibration points and the\n"
  56. "ones measured.")
  57. )
  58. grid_lay.addWidget(self.points_table_label, 2, 0, 1, 2)
  59. # BOTTOM LEFT
  60. self.bottom_left_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Bottom Left'))
  61. grid_lay.addWidget(self.bottom_left_lbl, 3, 0)
  62. self.bottom_left_tgt_lbl = QtWidgets.QLabel('%s' % _('Target'))
  63. grid_lay.addWidget(self.bottom_left_tgt_lbl, 3, 1)
  64. self.bottom_left_found_lbl = QtWidgets.QLabel('%s' % _('Found'))
  65. grid_lay.addWidget(self.bottom_left_found_lbl, 3, 2)
  66. self.bottom_left_coordx_lbl = QtWidgets.QLabel('%s' % _('X'))
  67. grid_lay.addWidget(self.bottom_left_coordx_lbl, 4, 0)
  68. self.bottom_left_coordx_tgt = EvalEntry()
  69. self.bottom_left_coordx_tgt.setDisabled(True)
  70. grid_lay.addWidget(self.bottom_left_coordx_tgt, 4, 1)
  71. self.bottom_left_coordx_found = EvalEntry()
  72. grid_lay.addWidget(self.bottom_left_coordx_found, 4, 2)
  73. self.bottom_left_coordy_lbl = QtWidgets.QLabel('%s' % _('Y'))
  74. grid_lay.addWidget(self.bottom_left_coordy_lbl, 5, 0)
  75. self.bottom_left_coordy_tgt = EvalEntry()
  76. self.bottom_left_coordy_tgt.setDisabled(True)
  77. grid_lay.addWidget(self.bottom_left_coordy_tgt, 5, 1)
  78. self.bottom_left_coordy_found = EvalEntry()
  79. grid_lay.addWidget(self.bottom_left_coordy_found, 5, 2)
  80. grid_lay.addWidget(QtWidgets.QLabel(''), 6, 0)
  81. self.bottom_left_coordx_found.set_value(_('Set Origin'))
  82. self.bottom_left_coordy_found.set_value(_('Set Origin'))
  83. self.bottom_left_coordx_found.setDisabled(True)
  84. self.bottom_left_coordy_found.setDisabled(True)
  85. # BOTTOM RIGHT
  86. self.bottom_right_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Bottom Right'))
  87. grid_lay.addWidget(self.bottom_right_lbl, 7, 0)
  88. self.bottom_right_tgt_lbl = QtWidgets.QLabel('%s' % _('Target'))
  89. grid_lay.addWidget(self.bottom_right_tgt_lbl, 7, 1)
  90. self.bottom_right_found_lbl = QtWidgets.QLabel('%s' % _('Found'))
  91. grid_lay.addWidget(self.bottom_right_found_lbl, 7, 2)
  92. self.bottom_right_coordx_lbl = QtWidgets.QLabel('%s' % _('X'))
  93. grid_lay.addWidget(self.bottom_right_coordx_lbl, 8, 0)
  94. self.bottom_right_coordx_tgt = EvalEntry()
  95. self.bottom_right_coordx_tgt.setDisabled(True)
  96. grid_lay.addWidget(self.bottom_right_coordx_tgt, 8, 1)
  97. self.bottom_right_coordx_found = EvalEntry()
  98. grid_lay.addWidget(self.bottom_right_coordx_found, 8, 2)
  99. self.bottom_right_coordy_lbl = QtWidgets.QLabel('%s' % _('Y'))
  100. grid_lay.addWidget(self.bottom_right_coordy_lbl, 9, 0)
  101. self.bottom_right_coordy_tgt = EvalEntry()
  102. self.bottom_right_coordy_tgt.setDisabled(True)
  103. grid_lay.addWidget(self.bottom_right_coordy_tgt, 9, 1)
  104. self.bottom_right_coordy_found = EvalEntry()
  105. grid_lay.addWidget(self.bottom_right_coordy_found, 9, 2)
  106. grid_lay.addWidget(QtWidgets.QLabel(''), 10, 0)
  107. # TOP LEFT
  108. self.top_left_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Top Left'))
  109. grid_lay.addWidget(self.top_left_lbl, 11, 0)
  110. self.top_left_tgt_lbl = QtWidgets.QLabel('%s' % _('Target'))
  111. grid_lay.addWidget(self.top_left_tgt_lbl, 11, 1)
  112. self.top_left_found_lbl = QtWidgets.QLabel('%s' % _('Found'))
  113. grid_lay.addWidget(self.top_left_found_lbl, 11, 2)
  114. self.top_left_coordx_lbl = QtWidgets.QLabel('%s' % _('X'))
  115. grid_lay.addWidget(self.top_left_coordx_lbl, 12, 0)
  116. self.top_left_coordx_tgt = EvalEntry()
  117. self.top_left_coordx_tgt.setDisabled(True)
  118. grid_lay.addWidget(self.top_left_coordx_tgt, 12, 1)
  119. self.top_left_coordx_found = EvalEntry()
  120. grid_lay.addWidget(self.top_left_coordx_found, 12, 2)
  121. self.top_left_coordy_lbl = QtWidgets.QLabel('%s' % _('Y'))
  122. grid_lay.addWidget(self.top_left_coordy_lbl, 13, 0)
  123. self.top_left_coordy_tgt = EvalEntry()
  124. self.top_left_coordy_tgt.setDisabled(True)
  125. grid_lay.addWidget(self.top_left_coordy_tgt, 13, 1)
  126. self.top_left_coordy_found = EvalEntry()
  127. grid_lay.addWidget(self.top_left_coordy_found, 13, 2)
  128. grid_lay.addWidget(QtWidgets.QLabel(''), 14, 0)
  129. # TOP RIGHT
  130. self.top_right_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Top Right'))
  131. grid_lay.addWidget(self.top_right_lbl, 15, 0)
  132. self.top_right_tgt_lbl = QtWidgets.QLabel('%s' % _('Target'))
  133. grid_lay.addWidget(self.top_right_tgt_lbl, 15, 1)
  134. self.top_right_found_lbl = QtWidgets.QLabel('%s' % _('Found'))
  135. grid_lay.addWidget(self.top_right_found_lbl, 15, 2)
  136. self.top_right_coordx_lbl = QtWidgets.QLabel('%s' % _('X'))
  137. grid_lay.addWidget(self.top_right_coordx_lbl, 16, 0)
  138. self.top_right_coordx_tgt = EvalEntry()
  139. self.top_right_coordx_tgt.setDisabled(True)
  140. grid_lay.addWidget(self.top_right_coordx_tgt, 16, 1)
  141. self.top_right_coordx_found = EvalEntry()
  142. grid_lay.addWidget(self.top_right_coordx_found, 16, 2)
  143. self.top_right_coordy_lbl = QtWidgets.QLabel('%s' % _('Y'))
  144. grid_lay.addWidget(self.top_right_coordy_lbl, 17, 0)
  145. self.top_right_coordy_tgt = EvalEntry()
  146. self.top_right_coordy_tgt.setDisabled(True)
  147. grid_lay.addWidget(self.top_right_coordy_tgt, 17, 1)
  148. self.top_right_coordy_found = EvalEntry()
  149. grid_lay.addWidget(self.top_right_coordy_found, 17, 2)
  150. grid_lay.addWidget(QtWidgets.QLabel(''), 18, 0)
  151. # ## Buttons
  152. self.start_button = QtWidgets.QPushButton(_("Start"))
  153. self.start_button.setToolTip(
  154. _("Start to collect four drill center coordinates,\n "
  155. "to be used as references. ")
  156. )
  157. self.layout.addWidget(self.start_button)
  158. self.layout.addStretch()
  159. self.mr = None
  160. self.units = ''
  161. # here store 4 points to be used for calibration
  162. self.click_points = list()
  163. self.exc_obj = None
  164. # ## Signals
  165. self.start_button.clicked.connect(self.on_start_collect_points)
  166. def run(self, toggle=True):
  167. self.app.report_usage("ToolCalibrateExcellon()")
  168. if toggle:
  169. # if the splitter is hidden, display it, else hide it but only if the current widget is the same
  170. if self.app.ui.splitter.sizes()[0] == 0:
  171. self.app.ui.splitter.setSizes([1, 1])
  172. else:
  173. try:
  174. if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
  175. # if tab is populated with the tool but it does not have the focus, focus on it
  176. if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
  177. # focus on Tool Tab
  178. self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
  179. else:
  180. self.app.ui.splitter.setSizes([0, 1])
  181. except AttributeError:
  182. pass
  183. else:
  184. if self.app.ui.splitter.sizes()[0] == 0:
  185. self.app.ui.splitter.setSizes([1, 1])
  186. FlatCAMTool.run(self)
  187. self.set_tool_ui()
  188. self.app.ui.notebook.setTabText(2, _("Cal Exc Tool"))
  189. def install(self, icon=None, separator=None, **kwargs):
  190. FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs)
  191. def set_tool_ui(self):
  192. self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
  193. # ## Initialize form
  194. # self.mm_entry.set_value('%.*f' % (self.decimals, 0))
  195. def on_start_collect_points(self):
  196. self.mr = self.canvas.graph_event_connect('mouse_release', self.on_mouse_click_release)
  197. if self.app.is_legacy is False:
  198. self.canvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
  199. else:
  200. self.canvas.graph_event_disconnect(self.app.mr)
  201. selection_index = self.exc_object_combo.currentIndex()
  202. model_index = self.app.collection.index(selection_index, 0, self.exc_object_combo.rootModelIndex())
  203. try:
  204. self.exc_obj = model_index.internalPointer().obj
  205. except Exception as e:
  206. self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
  207. return
  208. self.app.inform.emit(_("Click inside the First drill point. Bottom Left..."))
  209. def on_mouse_click_release(self, event):
  210. if event.button == 1:
  211. if self.app.is_legacy is False:
  212. event_pos = event.pos
  213. else:
  214. event_pos = (event.xdata, event.ydata)
  215. pos_canvas = self.canvas.translate_coords(event_pos)
  216. click_pt = Point([pos_canvas[0], pos_canvas[1]])
  217. for tool, tool_dict in self.exc_obj.tools.items():
  218. for geo in tool_dict['solid_geometry']:
  219. if click_pt.within(geo):
  220. center_pt = geo.centroid
  221. self.click_points.append(
  222. (
  223. float('%.*f' % (self.decimals, center_pt.x)),
  224. float('%.*f' % (self.decimals, center_pt.y))
  225. )
  226. )
  227. self.check_points()
  228. def check_points(self):
  229. if len(self.click_points) == 1:
  230. self.bottom_left_coordx_tgt.set_value(self.click_points[0][0])
  231. self.bottom_left_coordy_tgt.set_value(self.click_points[0][1])
  232. self.app.inform.emit(_("Click inside the Second drill point. Bottom Right..."))
  233. elif len(self.click_points) == 2:
  234. self.bottom_right_coordx_tgt.set_value(self.click_points[1][0])
  235. self.bottom_right_coordy_tgt.set_value(self.click_points[1][1])
  236. self.app.inform.emit(_("Click inside the Third drill point. Top Left..."))
  237. elif len(self.click_points) == 3:
  238. self.top_left_coordx_tgt.set_value(self.click_points[2][0])
  239. self.top_left_coordy_tgt.set_value(self.click_points[2][1])
  240. self.app.inform.emit(_("Click inside the Fourth drill point. Top Right..."))
  241. elif len(self.click_points) == 4:
  242. self.top_right_coordx_tgt.set_value(self.click_points[3][0])
  243. self.top_right_coordy_tgt.set_value(self.click_points[3][1])
  244. self.app.inform.emit('[success] %s' % _("Done. All four points have been acquired."))
  245. self.disconnect_cal_events()
  246. def disconnect_cal_events(self):
  247. self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
  248. if self.app.is_legacy is False:
  249. self.canvas.graph_event_disconnect('mouse_release', self.on_mouse_click_release)
  250. else:
  251. self.canvas.graph_event_disconnect(self.mr)
  252. def reset_fields(self):
  253. self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
  254. # end of file