- added support to use Multi Processing (multi core usage, not simple threading) in Rules Check Tool
- in Rules Check Tool added the functionality for the following rules: Hole Size, Trace Size, Hole to Hole Clerance
This commit is contained in:
@@ -7,6 +7,8 @@ from FlatCAMApp import App
|
|||||||
from flatcamGUI import VisPyPatches
|
from flatcamGUI import VisPyPatches
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
|
# import copyreg
|
||||||
|
# import types
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
# cx_freeze 'module win32' workaround
|
# cx_freeze 'module win32' workaround
|
||||||
|
|||||||
@@ -2778,11 +2778,11 @@ class App(QtCore.QObject):
|
|||||||
# recognize therefore we must quit but take into consideration the app reboot from within, in that case
|
# recognize therefore we must quit but take into consideration the app reboot from within, in that case
|
||||||
# the args_to_process will contain the path to the FlatCAM.exe (cx_freezed executable)
|
# the args_to_process will contain the path to the FlatCAM.exe (cx_freezed executable)
|
||||||
|
|
||||||
for arg in args_to_process:
|
# for arg in args_to_process:
|
||||||
if 'FlatCAM.exe' in arg:
|
# if 'FlatCAM.exe' in arg:
|
||||||
continue
|
# continue
|
||||||
else:
|
# else:
|
||||||
sys.exit(2)
|
# sys.exit(2)
|
||||||
|
|
||||||
def set_ui_title(self, name):
|
def set_ui_title(self, name):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ CAD program, and create G-Code for Isolation routing.
|
|||||||
- in Optimal Tool added display of how frequent that minimum distance is found
|
- in Optimal Tool added display of how frequent that minimum distance is found
|
||||||
- in Tool Distance and Tool Minimal Distance made the entry fields read-only
|
- in Tool Distance and Tool Minimal Distance made the entry fields read-only
|
||||||
- in Optimal Tool added the display of the locations where the minimum distance was detected
|
- in Optimal Tool added the display of the locations where the minimum distance was detected
|
||||||
|
- added support to use Multi Processing (multi core usage, not simple threading) in Rules Check Tool
|
||||||
|
- in Rules Check Tool added the functionality for the following rules: Hole Size, Trace Size, Hole to Hole Clerance
|
||||||
|
|
||||||
29.09.2019
|
29.09.2019
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ from ObjectCollection import *
|
|||||||
import time
|
import time
|
||||||
from FlatCAMPool import *
|
from FlatCAMPool import *
|
||||||
from os import getpid
|
from os import getpid
|
||||||
import copyreg, types, sys
|
from shapely.ops import nearest_points
|
||||||
|
from shapely.geometry.base import BaseGeometry
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
@@ -23,15 +24,6 @@ if '_' not in builtins.__dict__:
|
|||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
|
||||||
def _pickle_method(m):
|
|
||||||
class_self = m.im_class if m.im_self is None else m.im_self
|
|
||||||
print(getattr, (class_self, m.im_func.func_name))
|
|
||||||
return getattr, (class_self, m.im_func.func_name)
|
|
||||||
|
|
||||||
|
|
||||||
copyreg.pickle(types.MethodType, _pickle_method)
|
|
||||||
|
|
||||||
|
|
||||||
class RulesCheck(FlatCAMTool):
|
class RulesCheck(FlatCAMTool):
|
||||||
|
|
||||||
toolName = _("Check Rules")
|
toolName = _("Check Rules")
|
||||||
@@ -443,7 +435,7 @@ class RulesCheck(FlatCAMTool):
|
|||||||
|
|
||||||
self.form_layout_1.addRow(QtWidgets.QLabel(""))
|
self.form_layout_1.addRow(QtWidgets.QLabel(""))
|
||||||
|
|
||||||
# Drill2Drill clearance
|
# Hole2Hole clearance
|
||||||
self.clearance_d2d_cb = FCCheckBox('%s:' % _("Hole to Hole Clearance"))
|
self.clearance_d2d_cb = FCCheckBox('%s:' % _("Hole to Hole Clearance"))
|
||||||
self.clearance_d2d_cb.setToolTip(
|
self.clearance_d2d_cb.setToolTip(
|
||||||
_("This checks if the minimum clearance between a drill hole\n"
|
_("This checks if the minimum clearance between a drill hole\n"
|
||||||
@@ -451,7 +443,7 @@ class RulesCheck(FlatCAMTool):
|
|||||||
)
|
)
|
||||||
self.form_layout_1.addRow(self.clearance_d2d_cb)
|
self.form_layout_1.addRow(self.clearance_d2d_cb)
|
||||||
|
|
||||||
# Drill2Drill clearance value
|
# Hole2Hole clearance value
|
||||||
self.clearance_d2d_entry = FCEntry()
|
self.clearance_d2d_entry = FCEntry()
|
||||||
self.clearance_d2d_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
self.clearance_d2d_lbl = QtWidgets.QLabel('%s:' % _("Min value"))
|
||||||
self.clearance_d2d_lbl.setToolTip(
|
self.clearance_d2d_lbl.setToolTip(
|
||||||
@@ -527,6 +519,10 @@ class RulesCheck(FlatCAMTool):
|
|||||||
# flag to signal the constrain was activated
|
# flag to signal the constrain was activated
|
||||||
self.constrain_flag = False
|
self.constrain_flag = False
|
||||||
|
|
||||||
|
# Multiprocessing Process Pool
|
||||||
|
self.pool = Pool(processes=cpu_count())
|
||||||
|
self.results = None
|
||||||
|
|
||||||
# def on_object_loaded(self, index, row):
|
# def on_object_loaded(self, index, row):
|
||||||
# print(index.internalPointer().child_items[row].obj.options['name'], index.data())
|
# print(index.internalPointer().child_items[row].obj.options['name'], index.data())
|
||||||
|
|
||||||
@@ -598,34 +594,194 @@ class RulesCheck(FlatCAMTool):
|
|||||||
self.e2_object.setDisabled(True)
|
self.e2_object.setDisabled(True)
|
||||||
self.reset_fields()
|
self.reset_fields()
|
||||||
|
|
||||||
def foo(self, bar, baz):
|
@staticmethod
|
||||||
print("start", getpid())
|
def check_holes_size(elements, size):
|
||||||
bar = bar ** 2
|
rule = _("Hole Size")
|
||||||
print(bar, getpid())
|
|
||||||
print("end", getpid())
|
violations = list()
|
||||||
return bar, baz
|
obj_violations = dict()
|
||||||
|
obj_violations.update({
|
||||||
|
'name': '',
|
||||||
|
'dia': list()
|
||||||
|
})
|
||||||
|
|
||||||
|
for elem in elements:
|
||||||
|
dia_list = []
|
||||||
|
|
||||||
|
name = elem['name']
|
||||||
|
for tool in elem['tools']:
|
||||||
|
tool_dia = float(elem['tools'][tool]['C'])
|
||||||
|
if tool_dia < float(size):
|
||||||
|
dia_list.append(tool_dia)
|
||||||
|
obj_violations['name'] = name
|
||||||
|
obj_violations['dia'] = dia_list
|
||||||
|
violations.append(deepcopy(obj_violations))
|
||||||
|
|
||||||
|
return rule, violations
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_holes_clearance(elements, size):
|
||||||
|
rule = _("Hole to Hole Clearance")
|
||||||
|
|
||||||
|
violations = list()
|
||||||
|
obj_violations = dict()
|
||||||
|
obj_violations.update({
|
||||||
|
'name': '',
|
||||||
|
'points': list()
|
||||||
|
})
|
||||||
|
|
||||||
|
total_geo = list()
|
||||||
|
for elem in elements:
|
||||||
|
for tool in elem['tools']:
|
||||||
|
if 'solid_geometry' in elem['tools'][tool]:
|
||||||
|
geometry = elem['tools'][tool]['solid_geometry']
|
||||||
|
for geo in geometry:
|
||||||
|
total_geo.append(geo)
|
||||||
|
|
||||||
|
min_dict = dict()
|
||||||
|
idx = 1
|
||||||
|
for geo in total_geo:
|
||||||
|
for s_geo in total_geo[idx:]:
|
||||||
|
|
||||||
|
# minimize the number of distances by not taking into considerations those that are too small
|
||||||
|
dist = geo.distance(s_geo)
|
||||||
|
loc_1, loc_2 = nearest_points(geo, s_geo)
|
||||||
|
|
||||||
|
dx = loc_1.x - loc_2.x
|
||||||
|
dy = loc_1.y - loc_2.y
|
||||||
|
loc = min(loc_1.x, loc_2.x) + (abs(dx) / 2), min(loc_1.y, loc_2.y) + (abs(dy) / 2)
|
||||||
|
|
||||||
|
if dist in min_dict:
|
||||||
|
min_dict[dist].append(loc)
|
||||||
|
else:
|
||||||
|
min_dict[dist] = [loc]
|
||||||
|
idx += 1
|
||||||
|
|
||||||
|
points_list = list()
|
||||||
|
for dist in min_dict.keys():
|
||||||
|
if float(dist) < size:
|
||||||
|
for location in min_dict[dist]:
|
||||||
|
points_list.append(location)
|
||||||
|
|
||||||
|
name_list = list()
|
||||||
|
for elem in elements:
|
||||||
|
name_list.append(elem['name'])
|
||||||
|
|
||||||
|
obj_violations['name'] = name_list
|
||||||
|
obj_violations['points'] = points_list
|
||||||
|
violations.append(deepcopy(obj_violations))
|
||||||
|
|
||||||
|
return rule, violations
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_traces_size(elements, size):
|
||||||
|
rule = _("Trace Size")
|
||||||
|
|
||||||
|
violations = list()
|
||||||
|
obj_violations = dict()
|
||||||
|
obj_violations.update({
|
||||||
|
'name': '',
|
||||||
|
'size': list(),
|
||||||
|
'points': list()
|
||||||
|
})
|
||||||
|
|
||||||
|
for elem in elements:
|
||||||
|
dia_list = []
|
||||||
|
points_list = []
|
||||||
|
name = elem['name']
|
||||||
|
for apid in elem['apertures']:
|
||||||
|
tool_dia = float(elem['apertures'][apid]['size'])
|
||||||
|
if tool_dia < float(size):
|
||||||
|
dia_list.append(tool_dia)
|
||||||
|
for geo_el in elem['apertures'][apid]['geometry']:
|
||||||
|
if 'solid' in geo_el.keys():
|
||||||
|
geo = geo_el['solid']
|
||||||
|
pt = geo.representative_point()
|
||||||
|
points_list.append((pt.x, pt.y))
|
||||||
|
|
||||||
|
obj_violations['name'] = name
|
||||||
|
obj_violations['size'] = dia_list
|
||||||
|
obj_violations['points'] = points_list
|
||||||
|
violations.append(deepcopy(obj_violations))
|
||||||
|
|
||||||
|
return rule, violations
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
log.debug("started")
|
|
||||||
self.pool = Pool()
|
|
||||||
log.debug("executing")
|
|
||||||
self.results = list()
|
self.results = list()
|
||||||
i = 50
|
|
||||||
while i < 100:
|
|
||||||
j = i + 1
|
|
||||||
while j < 150:
|
|
||||||
self.results.append(self.pool.apply_async(self.foo, args=(i, j)))
|
|
||||||
j = j + 1
|
|
||||||
i = i + 1
|
|
||||||
|
|
||||||
output = [p.get() for p in self.results]
|
log.debug("RuleCheck() executing")
|
||||||
print(output)
|
|
||||||
log.debug("finished")
|
|
||||||
|
|
||||||
def __getstate__(self):
|
def worker_job(app_obj):
|
||||||
self_dict = self.__dict__.copy()
|
proc = self.app.proc_container.new(_("Working..."))
|
||||||
del self_dict['pool']
|
|
||||||
return self_dict
|
# RULE: Check Trace Size
|
||||||
|
if self.trace_size_cb.get_value():
|
||||||
|
copper_list = list()
|
||||||
|
copper_name_1 = self.copper_t_object.currentText()
|
||||||
|
if copper_name_1 is not '' and self.copper_t_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(copper_name_1)
|
||||||
|
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_1).apertures)
|
||||||
|
copper_list.append(elem_dict)
|
||||||
|
|
||||||
|
copper_name_2 = self.copper_b_object.currentText()
|
||||||
|
if copper_name_2 is not '' and self.copper_b_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(copper_name_2)
|
||||||
|
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_2).apertures)
|
||||||
|
copper_list.append(elem_dict)
|
||||||
|
|
||||||
|
trace_size = float(self.trace_size_entry.get_value())
|
||||||
|
self.results.append(self.pool.apply_async(self.check_traces_size, args=(copper_list, trace_size)))
|
||||||
|
|
||||||
|
# RULE: Check Hole to Hole Clearance
|
||||||
|
if self.clearance_d2d_cb.get_value():
|
||||||
|
exc_list = list()
|
||||||
|
exc_name_1 = self.e1_object.currentText()
|
||||||
|
if exc_name_1 is not '' and self.e1_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(exc_name_1)
|
||||||
|
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
|
||||||
|
exc_list.append(elem_dict)
|
||||||
|
|
||||||
|
exc_name_2 = self.e2_object.currentText()
|
||||||
|
if exc_name_2 is not '' and self.e2_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(exc_name_2)
|
||||||
|
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
|
||||||
|
exc_list.append(elem_dict)
|
||||||
|
|
||||||
|
hole_clearance = float(self.clearance_d2d_entry.get_value())
|
||||||
|
self.results.append(self.pool.apply_async(self.check_holes_clearance, args=(exc_list, hole_clearance)))
|
||||||
|
|
||||||
|
# RULE: Check Holes Size
|
||||||
|
if self.drill_size_cb.get_value():
|
||||||
|
exc_list = list()
|
||||||
|
exc_name_1 = self.e1_object.currentText()
|
||||||
|
if exc_name_1 is not '' and self.e1_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(exc_name_1)
|
||||||
|
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
|
||||||
|
exc_list.append(elem_dict)
|
||||||
|
|
||||||
|
exc_name_2 = self.e2_object.currentText()
|
||||||
|
if exc_name_2 is not '' and self.e2_cb.get_value():
|
||||||
|
elem_dict = dict()
|
||||||
|
elem_dict['name'] = deepcopy(exc_name_2)
|
||||||
|
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
|
||||||
|
exc_list.append(elem_dict)
|
||||||
|
|
||||||
|
drill_size = float(self.drill_size_entry.get_value())
|
||||||
|
self.results.append(self.pool.apply_async(self.check_holes_size, args=(exc_list, drill_size)))
|
||||||
|
|
||||||
|
output = list()
|
||||||
|
for p in self.results:
|
||||||
|
output.append(p.get())
|
||||||
|
|
||||||
|
print(output)
|
||||||
|
log.debug("RuleCheck() finished")
|
||||||
|
|
||||||
|
self.app.worker_task.emit({'fcn': worker_job, 'params': [self.app]})
|
||||||
|
|
||||||
def reset_fields(self):
|
def reset_fields(self):
|
||||||
# self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
# self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||||
|
|||||||
Reference in New Issue
Block a user