- updated the Rules Check Tool - solved some issues
This commit is contained in:
parent
bb88c43b36
commit
272c5c7453
|
@ -144,8 +144,8 @@ class App(QtCore.QObject):
|
|||
# Manual URL
|
||||
manual_url = "http://flatcam.org/manual/index.html"
|
||||
video_url = "https://www.youtube.com/playlist?list=PLVvP2SYRpx-AQgNlfoxw93tXUXon7G94_"
|
||||
gerber_spec_url ="https://www.ucamco.com/files/downloads/file/81/The_Gerber_File_Format_specification." \
|
||||
"pdf?7ac957791daba2cdf4c2c913f67a43da"
|
||||
gerber_spec_url = "https://www.ucamco.com/files/downloads/file/81/The_Gerber_File_Format_specification." \
|
||||
"pdf?7ac957791daba2cdf4c2c913f67a43da"
|
||||
excellon_spec_url = "https://www.ucamco.com/files/downloads/file/305/the_xnc_file_format_specification.pdf"
|
||||
bug_report_url = "https://bitbucket.org/jpcgt/flatcam/issues?status=new&status=open"
|
||||
|
||||
|
@ -2420,7 +2420,7 @@ class App(QtCore.QObject):
|
|||
self.move_tool = None
|
||||
self.cutout_tool = None
|
||||
self.ncclear_tool = None
|
||||
self.optimal_tool=None
|
||||
self.optimal_tool = None
|
||||
self.paint_tool = None
|
||||
self.transform_tool = None
|
||||
self.properties_tool = None
|
||||
|
@ -2561,6 +2561,9 @@ class App(QtCore.QObject):
|
|||
# set the value used in the Windows Title
|
||||
self.engine = self.ui.general_defaults_form.general_app_group.ge_radio.get_value()
|
||||
|
||||
# this will hold the TCL instance
|
||||
self.tcl = None
|
||||
|
||||
# ###############################################################################
|
||||
# ############# Save defaults to factory_defaults.FlatConfig file ###############
|
||||
# ############# It's done only once after install ###############
|
||||
|
@ -2859,7 +2862,7 @@ class App(QtCore.QObject):
|
|||
try:
|
||||
self.trayIcon.hide()
|
||||
except Exception as e:
|
||||
pass
|
||||
pass
|
||||
|
||||
fcTranslate.restart_program(app=self)
|
||||
|
||||
|
@ -4719,22 +4722,21 @@ class App(QtCore.QObject):
|
|||
f = open(data_path + "/current_defaults.FlatConfig", "w")
|
||||
json.dump(defaults, f, default=to_dict, indent=2, sort_keys=True)
|
||||
f.close()
|
||||
except:
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Failed to write defaults to file."))
|
||||
except Exception as e:
|
||||
log.debug("App.save_defaults() --> %s" % str(e))
|
||||
self.inform.emit(f'[ERROR_NOTCL] {_("Failed to write defaults to file.")}')
|
||||
return
|
||||
|
||||
if not silent:
|
||||
self.inform.emit('[success] %s' %
|
||||
_("Preferences saved."))
|
||||
self.inform.emit(f'[success] {_("Preferences saved.")}')
|
||||
|
||||
def save_factory_defaults(self, silent=False, data_path=None):
|
||||
def save_factory_defaults(self, silent_message=False, data_path=None):
|
||||
"""
|
||||
Saves application factory default options
|
||||
``self.defaults`` to factory_defaults.FlatConfig.
|
||||
It's a one time job done just after the first install.
|
||||
|
||||
:param silent: whether to display a message in status bar or not; boolean
|
||||
:param silent_message: whether to display a message in status bar or not; boolean
|
||||
:param data_path: the path where to save the default preferences file (factory_defaults.FlatConfig)
|
||||
When the application is portable it should be a mobile location.
|
||||
:return: None
|
||||
|
@ -4753,8 +4755,7 @@ class App(QtCore.QObject):
|
|||
e = sys.exc_info()[0]
|
||||
App.log.error("Could not load factory defaults file.")
|
||||
App.log.error(str(e))
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Could not load factory defaults file."))
|
||||
self.inform.emit(f'[ERROR_NOTCL] {_("Could not load factory defaults file.")}')
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -4763,8 +4764,7 @@ class App(QtCore.QObject):
|
|||
e = sys.exc_info()[0]
|
||||
App.log.error("Failed to parse factory defaults file.")
|
||||
App.log.error(str(e))
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Failed to parse factory defaults file."))
|
||||
self.inform.emit(f'[ERROR_NOTCL] {_("Failed to parse factory defaults file.")}')
|
||||
return
|
||||
|
||||
# Update options
|
||||
|
@ -4777,13 +4777,13 @@ class App(QtCore.QObject):
|
|||
f_f_def_s = open(data_path + "/factory_defaults.FlatConfig", "w")
|
||||
json.dump(factory_defaults, f_f_def_s, default=to_dict, indent=2, sort_keys=True)
|
||||
f_f_def_s.close()
|
||||
except:
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Failed to write factory defaults to file."))
|
||||
except Exception as e:
|
||||
log.debug(f"App.save_factory_default() save update --> {str(e)}")
|
||||
self.inform.emit(f'[ERROR_NOTCL] {_("Failed to write factory defaults to file.")}')
|
||||
return
|
||||
|
||||
if silent is False:
|
||||
self.inform.emit(_("Factory defaults saved."))
|
||||
if silent_message is False:
|
||||
self.inform.emit(f'{_("Factory defaults saved.")}')
|
||||
|
||||
def final_save(self):
|
||||
"""
|
||||
|
@ -4793,8 +4793,7 @@ class App(QtCore.QObject):
|
|||
:return: None
|
||||
"""
|
||||
if self.save_in_progress:
|
||||
self.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Application is saving the project. Please wait ..."))
|
||||
self.inform.emit(f'[WARNING_NOTCL] {_("Application is saving the project. Please wait ...")}')
|
||||
return
|
||||
|
||||
if self.should_we_save and self.collection.get_list():
|
||||
|
|
|
@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
=================================================
|
||||
|
||||
9.10.2019
|
||||
|
||||
- updated the Rules Check Tool - solved some issues
|
||||
|
||||
8.10.2019
|
||||
|
||||
- modified the FCSpinner and FCDoubleSpinner GUI elements such that the wheel event will not change the values inside unless there is a focus in the lineedit of the SpinBox
|
||||
|
|
|
@ -489,6 +489,8 @@ class RulesCheck(FlatCAMTool):
|
|||
self.pool = self.app.pool
|
||||
self.results = None
|
||||
|
||||
self.decimals = 4
|
||||
|
||||
# def on_object_loaded(self, index, row):
|
||||
# print(index.internalPointer().child_items[row].obj.options['name'], index.data())
|
||||
|
||||
|
@ -574,20 +576,37 @@ class RulesCheck(FlatCAMTool):
|
|||
if not gerber_obj:
|
||||
return 'Fail. Not enough Gerber objects to check Gerber 2 Gerber clearance'
|
||||
|
||||
total_geo = list()
|
||||
obj_violations['name'] = gerber_obj['name']
|
||||
|
||||
solid_geo = list()
|
||||
clear_geo = list()
|
||||
for apid in gerber_obj['apertures']:
|
||||
if 'geometry' in gerber_obj['apertures'][apid]:
|
||||
geometry = gerber_obj['apertures'][apid]['geometry']
|
||||
for geo_el in geometry:
|
||||
if 'solid' in geo_el and geo_el['solid'] is not None:
|
||||
total_geo.append(geo_el['solid'])
|
||||
solid_geo.append(geo_el['solid'])
|
||||
if 'clear' in geo_el and geo_el['clear'] is not None:
|
||||
clear_geo.append(geo_el['clear'])
|
||||
|
||||
total_geo = MultiPolygon(total_geo)
|
||||
total_geo = total_geo.buffer(0)
|
||||
if clear_geo:
|
||||
total_geo = list()
|
||||
for geo_c in clear_geo:
|
||||
for geo_s in solid_geo:
|
||||
if geo_c.within(geo_s):
|
||||
total_geo.append(geo_s.difference(geo_c))
|
||||
else:
|
||||
total_geo = MultiPolygon(solid_geo)
|
||||
total_geo = total_geo.buffer(0.000001)
|
||||
|
||||
iterations = len(total_geo)
|
||||
iterations = (iterations * (iterations - 1)) / 2
|
||||
if isinstance(total_geo, Polygon):
|
||||
iterations = 1
|
||||
obj_violations['points'] =['Failed. Only one polygon.']
|
||||
|
||||
return rule_title, [obj_violations]
|
||||
else:
|
||||
iterations = len(total_geo)
|
||||
iterations = (iterations * (iterations - 1)) / 2
|
||||
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
|
@ -608,14 +627,12 @@ class RulesCheck(FlatCAMTool):
|
|||
else:
|
||||
min_dict[dist] = [loc]
|
||||
idx += 1
|
||||
|
||||
points_list = list()
|
||||
points_list = set()
|
||||
for dist in min_dict.keys():
|
||||
for location in min_dict[dist]:
|
||||
points_list.append(location)
|
||||
points_list.add(location)
|
||||
|
||||
obj_violations['name'] = gerber_obj['name']
|
||||
obj_violations['points'] = points_list
|
||||
obj_violations['points'] = list(points_list)
|
||||
violations.append(deepcopy(obj_violations))
|
||||
|
||||
return rule_title, violations
|
||||
|
@ -675,7 +692,17 @@ class RulesCheck(FlatCAMTool):
|
|||
total_geo_grb_3 = MultiPolygon(total_geo_grb_3)
|
||||
total_geo_grb_3 = total_geo_grb_3.buffer(0)
|
||||
|
||||
iterations = len(total_geo_grb_1) * len(total_geo_grb_3)
|
||||
if isinstance(total_geo_grb_1, Polygon):
|
||||
len_1 = 1
|
||||
else:
|
||||
len_1 = len(total_geo_grb_1)
|
||||
|
||||
if isinstance(total_geo_grb_3, Polygon):
|
||||
len_3 = 1
|
||||
else:
|
||||
len_3 = len(total_geo_grb_3)
|
||||
|
||||
iterations = len_1 * len_3
|
||||
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
|
@ -905,7 +932,17 @@ class RulesCheck(FlatCAMTool):
|
|||
for geo in geometry:
|
||||
total_geo_exc.append(geo)
|
||||
|
||||
iterations = len(total_geo_grb) * len(total_geo_exc)
|
||||
if isinstance(total_geo_grb, Polygon):
|
||||
len_1 = 1
|
||||
else:
|
||||
len_1 = len(total_geo_grb)
|
||||
|
||||
if isinstance(total_geo_exc, Polygon):
|
||||
len_2 = 1
|
||||
else:
|
||||
len_2 = len(total_geo_exc)
|
||||
|
||||
iterations = len_1 * len_2
|
||||
log.debug("RulesCheck.check_gerber_annular_ring(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
|
@ -976,7 +1013,6 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Copper to Copper Clearance
|
||||
if self.clearance_copper2copper_cb.get_value():
|
||||
copper_dict = dict()
|
||||
|
||||
try:
|
||||
copper_copper_clearance = float(self.clearance_copper2copper_entry.get_value())
|
||||
|
@ -988,25 +1024,28 @@ class RulesCheck(FlatCAMTool):
|
|||
return
|
||||
|
||||
if self.copper_t_cb.get_value():
|
||||
copper_obj = self.copper_t_object.currentText()
|
||||
if copper_obj is not '':
|
||||
copper_dict['name'] = deepcopy(copper_obj)
|
||||
copper_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_obj).apertures)
|
||||
copper_t_obj = self.copper_t_object.currentText()
|
||||
copper_t_dict = dict()
|
||||
|
||||
if copper_t_obj is not '':
|
||||
copper_t_dict['name'] = deepcopy(copper_t_obj)
|
||||
copper_t_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_t_obj).apertures)
|
||||
|
||||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(copper_dict,
|
||||
args=(copper_t_dict,
|
||||
copper_copper_clearance,
|
||||
_("TOP: Copper to Copper clearance"))))
|
||||
_("TOP -> Copper to Copper clearance"))))
|
||||
if self.copper_b_cb.get_value():
|
||||
copper_obj = self.copper_b_object.currentText()
|
||||
if copper_obj is not '':
|
||||
copper_dict['name'] = deepcopy(copper_obj)
|
||||
copper_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_obj).apertures)
|
||||
copper_b_obj = self.copper_b_object.currentText()
|
||||
copper_b_dict = dict()
|
||||
if copper_b_obj is not '':
|
||||
copper_b_dict['name'] = deepcopy(copper_b_obj)
|
||||
copper_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_b_obj).apertures)
|
||||
|
||||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(copper_dict,
|
||||
args=(copper_b_dict,
|
||||
copper_copper_clearance,
|
||||
_("BOTTOM: Copper to Copper clearance"))))
|
||||
_("BOTTOM -> Copper to Copper clearance"))))
|
||||
|
||||
if self.copper_t_cb.get_value() is False and self.copper_b_cb.get_value() is False:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
|
||||
|
@ -1090,7 +1129,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(silk_dict,
|
||||
silk_silk_clearance,
|
||||
_("TOP: Silk to Silk clearance"))))
|
||||
_("TOP -> Silk to Silk clearance"))))
|
||||
if self.ss_b_cb.get_value():
|
||||
silk_obj = self.ss_b_object.currentText()
|
||||
if silk_obj is not '':
|
||||
|
@ -1100,7 +1139,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(silk_dict,
|
||||
silk_silk_clearance,
|
||||
_("BOTTOM: Silk to Silk clearance"))))
|
||||
_("BOTTOM -> Silk to Silk clearance"))))
|
||||
|
||||
if self.ss_t_cb.get_value() is False and self.ss_b_cb.get_value() is False:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
|
||||
|
@ -1164,13 +1203,13 @@ class RulesCheck(FlatCAMTool):
|
|||
self.results.append(self.pool.apply_async(self.check_gerber_clearance,
|
||||
args=(objs,
|
||||
silk_sm_clearance,
|
||||
_("TOP: Silk to Solder Mask Clearance"))))
|
||||
_("TOP -> Silk to Solder Mask Clearance"))))
|
||||
elif bottom_ss is True and bottom_sm is True:
|
||||
objs = [silk_b_dict, sm_b_dict]
|
||||
self.results.append(self.pool.apply_async(self.check_gerber_clearance,
|
||||
args=(objs,
|
||||
silk_sm_clearance,
|
||||
_("BOTTOM: Silk to Solder Mask Clearance"))))
|
||||
_("BOTTOM -> Silk to Solder Mask Clearance"))))
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
|
||||
_("Silk to Solder Mask Clearance"),
|
||||
|
@ -1254,7 +1293,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(sm_dict,
|
||||
sm_sm_clearance,
|
||||
_("TOP: Minimum Solder Mask Sliver"))))
|
||||
_("TOP -> Minimum Solder Mask Sliver"))))
|
||||
if self.sm_b_cb.get_value():
|
||||
solder_obj = self.sm_b_object.currentText()
|
||||
if solder_obj is not '':
|
||||
|
@ -1264,7 +1303,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.results.append(self.pool.apply_async(self.check_inside_gerber_clearance,
|
||||
args=(sm_dict,
|
||||
sm_sm_clearance,
|
||||
_("BOTTOM: Minimum Solder Mask Sliver"))))
|
||||
_("BOTTOM -> Minimum Solder Mask Sliver"))))
|
||||
|
||||
if self.sm_t_cb.get_value() is False and self.sm_b_cb.get_value() is False:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s. %s' % (
|
||||
|
@ -1391,29 +1430,31 @@ class RulesCheck(FlatCAMTool):
|
|||
def init(new_obj, app_obj):
|
||||
txt = ''
|
||||
for el in res:
|
||||
txt += '<b>RULE NAME:</b>\t%s\n' % str(el[0]).upper()
|
||||
txt += '<b>RULE NAME:</b> %s<BR>' % str(el[0]).upper()
|
||||
if isinstance(el[1][0]['name'], list):
|
||||
for name in el[1][0]['name']:
|
||||
txt += 'File name: %s\n' % str(name)
|
||||
else:
|
||||
txt += 'File name: %s\n' % str(el[1][0]['name'])
|
||||
txt += 'File name: %s<BR>' % str(name)
|
||||
else:
|
||||
txt += 'File name: %s<BR>' % str(el[1][0]['name'])
|
||||
|
||||
point_txt = ''
|
||||
if el[1][0]['points']:
|
||||
txt += '{title}: <span style="color:{color};">{status}</span>.\n'.format(title=_("STATUS"),
|
||||
color='red',
|
||||
status=_("FAILED"))
|
||||
|
||||
for pt in el[1][0]['points']:
|
||||
point_txt += str(pt)
|
||||
point_txt += ', '
|
||||
txt += 'Violations: %s\n' % str(point_txt)
|
||||
txt += '{title}: <span style="color:{color};">{status}</span>.<BR>'.format(title=_("STATUS"),
|
||||
color='red',
|
||||
status=_("FAILED"))
|
||||
if 'Failed' in el[1][0]['points'][0]:
|
||||
point_txt = el[1][0]['points'][0]
|
||||
else:
|
||||
for pt in el[1][0]['points']:
|
||||
point_txt += '(%.*f, %.*f)' % (self.decimals, float(pt[0]), self.decimals, float(pt[1]))
|
||||
point_txt += ', '
|
||||
txt += 'Violations: %s<BR>' % str(point_txt)
|
||||
else:
|
||||
txt += '{title}: <span style="color:{color};">{status}</span>.\n'.format(title=_("STATUS"),
|
||||
color='green',
|
||||
status=_("PASSED"))
|
||||
txt += '%s\n' % _("Violations: There are no violations for the current rule.")
|
||||
txt += '\n\n'
|
||||
txt += '{title}: <span style="color:{color};">{status}</span>.<BR>'.format(title=_("STATUS"),
|
||||
color='green',
|
||||
status=_("PASSED"))
|
||||
txt += '%s<BR>' % _("Violations: There are no violations for the current rule.")
|
||||
txt += '<BR><BR>'
|
||||
new_obj.source_file = txt
|
||||
new_obj.read_only = True
|
||||
|
||||
|
|
Loading…
Reference in New Issue