- made the splashscreen to be showed on the current monitor on systems with multiple monitors
- added a new entry in Menu -> View -> Redraw All which is doing what the name says: redraw all loaded objects - fixed issue where in TCl Shell the Windows paths were not understood due of backslash symbol understood as escape symbol instead of path separator - made sure that in for the TclCommand cncjob and for the drillcncjob if one of the args is stated but no value then the value used will be the default one - made available the TSA algorithm for drill path optimization when the used OS is 64bit. When used OS is 32bit the only available algorithm is TSA
This commit is contained in:
parent
81c0ee5638
commit
f51a3fa038
|
@ -361,6 +361,13 @@ class App(QtCore.QObject):
|
|||
splash_pix = QtGui.QPixmap('share/splash.png')
|
||||
splash = QtWidgets.QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
|
||||
# splash.setMask(splash_pix.mask())
|
||||
|
||||
# move splashscreen to the current monitor
|
||||
desktop = QtWidgets.QApplication.desktop()
|
||||
screen = desktop.screenNumber(QtGui.QCursor.pos())
|
||||
current_screen_center = desktop.availableGeometry(screen).center()
|
||||
splash.move(current_screen_center - splash.rect().center())
|
||||
|
||||
splash.show()
|
||||
splash.showMessage(_("FlatCAM is initializing ..."),
|
||||
alignment=Qt.AlignBottom | Qt.AlignLeft,
|
||||
|
@ -1695,6 +1702,7 @@ class App(QtCore.QObject):
|
|||
self.ui.menuview_zoom_fit.triggered.connect(self.on_zoom_fit)
|
||||
self.ui.menuview_zoom_in.triggered.connect(self.on_zoom_in)
|
||||
self.ui.menuview_zoom_out.triggered.connect(self.on_zoom_out)
|
||||
self.ui.menuview_replot.triggered.connect(self.plot_all)
|
||||
|
||||
self.ui.menuview_toggle_code_editor.triggered.connect(self.on_toggle_code_editor)
|
||||
self.ui.menuview_toggle_fscreen.triggered.connect(self.on_fullscreen)
|
||||
|
@ -2145,6 +2153,22 @@ class App(QtCore.QObject):
|
|||
|
||||
self.myKeywords = self.tcl_commands_list + self.ordinary_keywords + self.tcl_keywords
|
||||
|
||||
self.default_autocomplete_keywords = [
|
||||
'all', 'angle_x', 'angle_y', 'axis', 'axisoffset', 'box', 'center_x', 'center_y',
|
||||
'columns', 'combine', 'connect', 'contour', 'depthperpass', 'dia', 'diatol', 'dist',
|
||||
'drilled_dias', 'drillz', 'pp',
|
||||
'gridoffsety', 'gridx', 'gridy', 'has_offset', 'holes', 'margin', 'method',
|
||||
'milled_dias',
|
||||
'minoffset', 'multidepth', 'name', 'offset', 'opt_type', 'order', 'outname',
|
||||
'overlap', 'passes', 'postamble', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref',
|
||||
'rest', 'rows', 'scale_factor', 'spacing_columns', 'spacing_rows', 'spindlespeed',
|
||||
'use_threads', 'value', 'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move',
|
||||
'default', 'feedrate_z', 'grbl_11', 'grbl_laser', 'hpgl', 'line_xyz', 'marlin',
|
||||
'Paste_1', 'Repetier', 'Toolchange_Custom', 'Roland_MDX_20', 'Toolchange_manual',
|
||||
'Toolchange_Probe_MACH3', 'dwell', 'dwelltime', 'toolchange_xy', 'iso_type',
|
||||
'Desktop', 'FlatPrj', 'FlatConfig', 'Users', 'Documents', 'My Documents', 'Marius'
|
||||
]
|
||||
|
||||
# ####################################################################################
|
||||
# ####################### Shell SETUP ################################################
|
||||
# ####################################################################################
|
||||
|
@ -2368,6 +2392,12 @@ class App(QtCore.QObject):
|
|||
# finish the splash
|
||||
# splash.finish(self.ui)
|
||||
|
||||
# disable the Excellon path optimizations made with Google OR-Tools if the app is run on a 32bit platform
|
||||
current_platform = platform.architecture()[0]
|
||||
if current_platform != '64bit':
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio.set_value('T')
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio.setDisabled(True)
|
||||
|
||||
# ###############################################################################
|
||||
# ####################### Finished the CONSTRUCTOR ##############################
|
||||
# ###############################################################################
|
||||
|
@ -9789,6 +9819,7 @@ class App(QtCore.QObject):
|
|||
:return: None
|
||||
"""
|
||||
self.log.debug("Plot_all()")
|
||||
self.inform.emit('[success] %s...' % _("Redrawing all objects"))
|
||||
|
||||
for obj in self.collection.get_list():
|
||||
def worker_task(obj):
|
||||
|
|
|
@ -20,6 +20,11 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- fixed some issues recently introduced in the TclCommands CNCJob, DrillCNCJob and write_gcode; changed some parameters names
|
||||
- fixed issue in the Laser postprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
|
||||
- added new links in Menu -> Help (Excellon, Gerber specifications and a Report Bug)
|
||||
- made the splashscreen to be showed on the current monitor on systems with multiple monitors
|
||||
- added a new entry in Menu -> View -> Redraw All which is doing what the name says: redraw all loaded objects
|
||||
- fixed issue where in TCl Shell the Windows paths were not understood due of backslash symbol understood as escape symbol instead of path separator
|
||||
- made sure that in for the TclCommand cncjob and for the drillcncjob if one of the args is stated but no value then the value used will be the default one
|
||||
- made available the TSA algorithm for drill path optimization when the used OS is 64bit. When used OS is 32bit the only available algorithm is TSA
|
||||
|
||||
15.09.2019
|
||||
|
||||
|
|
575
camlib.py
575
camlib.py
|
@ -5867,318 +5867,313 @@ class CNCjob(Geometry):
|
|||
|
||||
self.app.inform.emit('%s...' %
|
||||
_("Starting G-Code"))
|
||||
current_platform = platform.architecture()[0]
|
||||
if current_platform == '64bit':
|
||||
if excellon_optimization_type == 'M':
|
||||
log.debug("Using OR-Tools Metaheuristic Guided Local Search drill path optimization.")
|
||||
if exobj.drills:
|
||||
for tool in tools:
|
||||
self.tool=tool
|
||||
self.postdata['toolC'] = exobj.tools[tool]["C"]
|
||||
self.tooldia = exobj.tools[tool]["C"]
|
||||
|
||||
if excellon_optimization_type == 'M':
|
||||
log.debug("Using OR-Tools Metaheuristic Guided Local Search drill path optimization.")
|
||||
if exobj.drills:
|
||||
for tool in tools:
|
||||
self.tool=tool
|
||||
self.postdata['toolC'] = exobj.tools[tool]["C"]
|
||||
self.tooldia = exobj.tools[tool]["C"]
|
||||
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
# ###############################################
|
||||
# ############ Create the data. #################
|
||||
# ###############################################
|
||||
|
||||
node_list = []
|
||||
locations = create_data_array()
|
||||
tsp_size = len(locations)
|
||||
num_routes = 1 # The number of routes, which is 1 in the TSP.
|
||||
# Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route.
|
||||
depot = 0
|
||||
# Create routing model.
|
||||
if tsp_size > 0:
|
||||
manager = pywrapcp.RoutingIndexManager(tsp_size, num_routes, depot)
|
||||
routing = pywrapcp.RoutingModel(manager)
|
||||
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
|
||||
search_parameters.local_search_metaheuristic = (
|
||||
routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
|
||||
|
||||
# Set search time limit in milliseconds.
|
||||
if float(self.app.defaults["excellon_search_time"]) != 0:
|
||||
search_parameters.time_limit.seconds = int(
|
||||
float(self.app.defaults["excellon_search_time"]))
|
||||
else:
|
||||
search_parameters.time_limit.seconds = 3
|
||||
|
||||
# Callback to the distance function. The callback takes two
|
||||
# arguments (the from and to node indices) and returns the distance between them.
|
||||
dist_between_locations = CreateDistanceCallback()
|
||||
dist_callback = dist_between_locations.Distance
|
||||
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
|
||||
|
||||
# Solve, returns a solution if any.
|
||||
assignment = routing.SolveWithParameters(search_parameters)
|
||||
|
||||
if assignment:
|
||||
# Solution cost.
|
||||
log.info("Total distance: " + str(assignment.ObjectiveValue()))
|
||||
|
||||
# Inspect solution.
|
||||
# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1.
|
||||
route_number = 0
|
||||
node = routing.Start(route_number)
|
||||
start_node = node
|
||||
|
||||
while not routing.IsEnd(node):
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
node_list.append(node)
|
||||
node = assignment.Value(routing.NextVar(node))
|
||||
else:
|
||||
log.warning('No solution found.')
|
||||
else:
|
||||
log.warning('Specify an instance greater than 0.')
|
||||
# ############################################# ##
|
||||
|
||||
# Only if tool has points.
|
||||
if tool in points:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
# ###############################################
|
||||
# ############ Create the data. #################
|
||||
# ###############################################
|
||||
|
||||
node_list = []
|
||||
locations = create_data_array()
|
||||
tsp_size = len(locations)
|
||||
num_routes = 1 # The number of routes, which is 1 in the TSP.
|
||||
# Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route.
|
||||
depot = 0
|
||||
# Create routing model.
|
||||
if tsp_size > 0:
|
||||
manager = pywrapcp.RoutingIndexManager(tsp_size, num_routes, depot)
|
||||
routing = pywrapcp.RoutingModel(manager)
|
||||
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
|
||||
search_parameters.local_search_metaheuristic = (
|
||||
routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
|
||||
|
||||
# Set search time limit in milliseconds.
|
||||
if float(self.app.defaults["excellon_search_time"]) != 0:
|
||||
search_parameters.time_limit.seconds = int(
|
||||
float(self.app.defaults["excellon_search_time"]))
|
||||
else:
|
||||
search_parameters.time_limit.seconds = 3
|
||||
|
||||
# Callback to the distance function. The callback takes two
|
||||
# arguments (the from and to node indices) and returns the distance between them.
|
||||
dist_between_locations = CreateDistanceCallback()
|
||||
dist_callback = dist_between_locations.Distance
|
||||
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
|
||||
|
||||
# Solve, returns a solution if any.
|
||||
assignment = routing.SolveWithParameters(search_parameters)
|
||||
|
||||
if assignment:
|
||||
# Solution cost.
|
||||
log.info("Total distance: " + str(assignment.ObjectiveValue()))
|
||||
|
||||
# Inspect solution.
|
||||
# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1.
|
||||
route_number = 0
|
||||
node = routing.Start(route_number)
|
||||
start_node = node
|
||||
|
||||
while not routing.IsEnd(node):
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
node_list.append(node)
|
||||
node = assignment.Value(routing.NextVar(node))
|
||||
else:
|
||||
log.warning('No solution found.')
|
||||
# Tool change sequence (optional)
|
||||
if toolchange:
|
||||
gcode += self.doformat(p.toolchange_code,toolchangexy=(self.oldx, self.oldy))
|
||||
gcode += self.doformat(p.spindle_code) # Spindle start
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
else:
|
||||
log.warning('Specify an instance greater than 0.')
|
||||
# ############################################# ##
|
||||
gcode += self.doformat(p.spindle_code)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
|
||||
# Only if tool has points.
|
||||
if tool in points:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
# Tool change sequence (optional)
|
||||
if toolchange:
|
||||
gcode += self.doformat(p.toolchange_code,toolchangexy=(self.oldx, self.oldy))
|
||||
gcode += self.doformat(p.spindle_code) # Spindle start
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
else:
|
||||
gcode += self.doformat(p.spindle_code)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
|
||||
if self.units == 'MM':
|
||||
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
|
||||
else:
|
||||
current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
|
||||
|
||||
self.app.inform.emit(
|
||||
'%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
|
||||
str(current_tooldia),
|
||||
str(self.units))
|
||||
)
|
||||
|
||||
# TODO apply offset only when using the GUI, for TclCommand this will create an error
|
||||
# because the values for Z offset are created in build_ui()
|
||||
try:
|
||||
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
|
||||
except KeyError:
|
||||
z_offset = 0
|
||||
self.z_cut += z_offset
|
||||
|
||||
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
|
||||
if self.coordinates_type == "G90":
|
||||
# Drillling! for Absolute coordinates type G90
|
||||
# variables to display the percentage of work done
|
||||
geo_len = len(node_list)
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
|
||||
|
||||
loc_nr = 0
|
||||
for k in node_list:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
gcode += self.doformat(p.down_code, x=locx, y=locy)
|
||||
|
||||
measured_down_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
if self.f_retract is False:
|
||||
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
|
||||
measured_up_to_zero_distance += abs(self.z_cut)
|
||||
measured_lift_distance += abs(self.z_move)
|
||||
else:
|
||||
measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
gcode += self.doformat(p.lift_code, x=locx, y=locy)
|
||||
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
|
||||
self.oldx = locx
|
||||
self.oldy = locy
|
||||
|
||||
loc_nr += 1
|
||||
disp_number = int(np.interp(loc_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('G91 coordinates not implemented'))
|
||||
return 'fail'
|
||||
else:
|
||||
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> "
|
||||
"The loaded Excellon file has no drills ...")
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('The loaded Excellon file has no drills'))
|
||||
return 'fail'
|
||||
|
||||
log.debug("The total travel distance with OR-TOOLS Metaheuristics is: %s" % str(measured_distance))
|
||||
elif excellon_optimization_type == 'B':
|
||||
log.debug("Using OR-Tools Basic drill path optimization.")
|
||||
if exobj.drills:
|
||||
for tool in tools:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
self.tool=tool
|
||||
self.postdata['toolC']=exobj.tools[tool]["C"]
|
||||
self.tooldia = exobj.tools[tool]["C"]
|
||||
|
||||
# ############################################# ##
|
||||
node_list = []
|
||||
locations = create_data_array()
|
||||
tsp_size = len(locations)
|
||||
num_routes = 1 # The number of routes, which is 1 in the TSP.
|
||||
|
||||
# Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route.
|
||||
depot = 0
|
||||
|
||||
# Create routing model.
|
||||
if tsp_size > 0:
|
||||
manager = pywrapcp.RoutingIndexManager(tsp_size, num_routes, depot)
|
||||
routing = pywrapcp.RoutingModel(manager)
|
||||
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
|
||||
|
||||
# Callback to the distance function. The callback takes two
|
||||
# arguments (the from and to node indices) and returns the distance between them.
|
||||
dist_between_locations = CreateDistanceCallback()
|
||||
dist_callback = dist_between_locations.Distance
|
||||
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
|
||||
|
||||
# Solve, returns a solution if any.
|
||||
assignment = routing.SolveWithParameters(search_parameters)
|
||||
|
||||
if assignment:
|
||||
# Solution cost.
|
||||
log.info("Total distance: " + str(assignment.ObjectiveValue()))
|
||||
|
||||
# Inspect solution.
|
||||
# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1.
|
||||
route_number = 0
|
||||
node = routing.Start(route_number)
|
||||
start_node = node
|
||||
|
||||
while not routing.IsEnd(node):
|
||||
node_list.append(node)
|
||||
node = assignment.Value(routing.NextVar(node))
|
||||
else:
|
||||
log.warning('No solution found.')
|
||||
if self.units == 'MM':
|
||||
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
|
||||
else:
|
||||
log.warning('Specify an instance greater than 0.')
|
||||
# ############################################# ##
|
||||
current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
|
||||
|
||||
# Only if tool has points.
|
||||
if tool in points:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
self.app.inform.emit(
|
||||
'%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
|
||||
str(current_tooldia),
|
||||
str(self.units))
|
||||
)
|
||||
|
||||
# Tool change sequence (optional)
|
||||
if toolchange:
|
||||
gcode += self.doformat(p.toolchange_code,toolchangexy=(self.oldx, self.oldy))
|
||||
gcode += self.doformat(p.spindle_code) # Spindle start)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
else:
|
||||
gcode += self.doformat(p.spindle_code)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
# TODO apply offset only when using the GUI, for TclCommand this will create an error
|
||||
# because the values for Z offset are created in build_ui()
|
||||
try:
|
||||
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
|
||||
except KeyError:
|
||||
z_offset = 0
|
||||
self.z_cut += z_offset
|
||||
|
||||
if self.units == 'MM':
|
||||
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
|
||||
else:
|
||||
current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
|
||||
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
|
||||
if self.coordinates_type == "G90":
|
||||
# Drillling! for Absolute coordinates type G90
|
||||
# variables to display the percentage of work done
|
||||
geo_len = len(node_list)
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
|
||||
|
||||
self.app.inform.emit(
|
||||
'%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
|
||||
str(current_tooldia),
|
||||
str(self.units))
|
||||
)
|
||||
loc_nr = 0
|
||||
for k in node_list:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
# TODO apply offset only when using the GUI, for TclCommand this will create an error
|
||||
# because the values for Z offset are created in build_ui()
|
||||
try:
|
||||
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
|
||||
except KeyError:
|
||||
z_offset = 0
|
||||
self.z_cut += z_offset
|
||||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
|
||||
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
|
||||
if self.coordinates_type == "G90":
|
||||
# Drillling! for Absolute coordinates type G90
|
||||
# variables to display the percentage of work done
|
||||
geo_len = len(node_list)
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
gcode += self.doformat(p.down_code, x=locx, y=locy)
|
||||
|
||||
loc_nr = 0
|
||||
for k in node_list:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
measured_down_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
if self.f_retract is False:
|
||||
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
|
||||
measured_up_to_zero_distance += abs(self.z_cut)
|
||||
measured_lift_distance += abs(self.z_move)
|
||||
else:
|
||||
measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
gcode += self.doformat(p.down_code, x=locx, y=locy)
|
||||
gcode += self.doformat(p.lift_code, x=locx, y=locy)
|
||||
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
|
||||
self.oldx = locx
|
||||
self.oldy = locy
|
||||
|
||||
measured_down_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
loc_nr += 1
|
||||
disp_number = int(np.interp(loc_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
if self.f_retract is False:
|
||||
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
|
||||
measured_up_to_zero_distance += abs(self.z_cut)
|
||||
measured_lift_distance += abs(self.z_move)
|
||||
else:
|
||||
measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
|
||||
gcode += self.doformat(p.lift_code, x=locx, y=locy)
|
||||
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
|
||||
self.oldx = locx
|
||||
self.oldy = locy
|
||||
|
||||
loc_nr += 1
|
||||
disp_number = int(np.interp(loc_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('G91 coordinates not implemented'))
|
||||
return 'fail'
|
||||
else:
|
||||
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> "
|
||||
"The loaded Excellon file has no drills ...")
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('The loaded Excellon file has no drills'))
|
||||
return 'fail'
|
||||
|
||||
log.debug("The total travel distance with OR-TOOLS Basic Algorithm is: %s" % str(measured_distance))
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('G91 coordinates not implemented'))
|
||||
return 'fail'
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Wrong optimization type selected."))
|
||||
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> "
|
||||
"The loaded Excellon file has no drills ...")
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('The loaded Excellon file has no drills'))
|
||||
return 'fail'
|
||||
|
||||
log.debug("The total travel distance with OR-TOOLS Metaheuristics is: %s" % str(measured_distance))
|
||||
elif excellon_optimization_type == 'B':
|
||||
log.debug("Using OR-Tools Basic drill path optimization.")
|
||||
if exobj.drills:
|
||||
for tool in tools:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
self.tool=tool
|
||||
self.postdata['toolC']=exobj.tools[tool]["C"]
|
||||
self.tooldia = exobj.tools[tool]["C"]
|
||||
|
||||
# ############################################# ##
|
||||
node_list = []
|
||||
locations = create_data_array()
|
||||
tsp_size = len(locations)
|
||||
num_routes = 1 # The number of routes, which is 1 in the TSP.
|
||||
|
||||
# Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route.
|
||||
depot = 0
|
||||
|
||||
# Create routing model.
|
||||
if tsp_size > 0:
|
||||
manager = pywrapcp.RoutingIndexManager(tsp_size, num_routes, depot)
|
||||
routing = pywrapcp.RoutingModel(manager)
|
||||
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
|
||||
|
||||
# Callback to the distance function. The callback takes two
|
||||
# arguments (the from and to node indices) and returns the distance between them.
|
||||
dist_between_locations = CreateDistanceCallback()
|
||||
dist_callback = dist_between_locations.Distance
|
||||
transit_callback_index = routing.RegisterTransitCallback(dist_callback)
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
|
||||
|
||||
# Solve, returns a solution if any.
|
||||
assignment = routing.SolveWithParameters(search_parameters)
|
||||
|
||||
if assignment:
|
||||
# Solution cost.
|
||||
log.info("Total distance: " + str(assignment.ObjectiveValue()))
|
||||
|
||||
# Inspect solution.
|
||||
# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1.
|
||||
route_number = 0
|
||||
node = routing.Start(route_number)
|
||||
start_node = node
|
||||
|
||||
while not routing.IsEnd(node):
|
||||
node_list.append(node)
|
||||
node = assignment.Value(routing.NextVar(node))
|
||||
else:
|
||||
log.warning('No solution found.')
|
||||
else:
|
||||
log.warning('Specify an instance greater than 0.')
|
||||
# ############################################# ##
|
||||
|
||||
# Only if tool has points.
|
||||
if tool in points:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
# Tool change sequence (optional)
|
||||
if toolchange:
|
||||
gcode += self.doformat(p.toolchange_code,toolchangexy=(self.oldx, self.oldy))
|
||||
gcode += self.doformat(p.spindle_code) # Spindle start)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
else:
|
||||
gcode += self.doformat(p.spindle_code)
|
||||
if self.dwell is True:
|
||||
gcode += self.doformat(p.dwell_code) # Dwell time
|
||||
|
||||
if self.units == 'MM':
|
||||
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
|
||||
else:
|
||||
current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
|
||||
|
||||
self.app.inform.emit(
|
||||
'%s: %s%s.' % (_("Starting G-Code for tool with diameter"),
|
||||
str(current_tooldia),
|
||||
str(self.units))
|
||||
)
|
||||
|
||||
# TODO apply offset only when using the GUI, for TclCommand this will create an error
|
||||
# because the values for Z offset are created in build_ui()
|
||||
try:
|
||||
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
|
||||
except KeyError:
|
||||
z_offset = 0
|
||||
self.z_cut += z_offset
|
||||
|
||||
self.coordinates_type = self.app.defaults["cncjob_coords_type"]
|
||||
if self.coordinates_type == "G90":
|
||||
# Drillling! for Absolute coordinates type G90
|
||||
# variables to display the percentage of work done
|
||||
geo_len = len(node_list)
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
log.warning("Number of drills for which to generate GCode: %s" % str(geo_len))
|
||||
|
||||
loc_nr = 0
|
||||
for k in node_list:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
gcode += self.doformat(p.down_code, x=locx, y=locy)
|
||||
|
||||
measured_down_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
if self.f_retract is False:
|
||||
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
|
||||
measured_up_to_zero_distance += abs(self.z_cut)
|
||||
measured_lift_distance += abs(self.z_move)
|
||||
else:
|
||||
measured_lift_distance += abs(self.z_cut) + abs(self.z_move)
|
||||
|
||||
gcode += self.doformat(p.lift_code, x=locx, y=locy)
|
||||
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
|
||||
self.oldx = locx
|
||||
self.oldy = locy
|
||||
|
||||
loc_nr += 1
|
||||
disp_number = int(np.interp(loc_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('G91 coordinates not implemented'))
|
||||
return 'fail'
|
||||
else:
|
||||
log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> "
|
||||
"The loaded Excellon file has no drills ...")
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s...' %
|
||||
_('The loaded Excellon file has no drills'))
|
||||
return 'fail'
|
||||
|
||||
log.debug("The total travel distance with OR-TOOLS Basic Algorithm is: %s" % str(measured_distance))
|
||||
else:
|
||||
log.debug("Using Travelling Salesman drill path optimization.")
|
||||
for tool in tools:
|
||||
|
|
|
@ -372,6 +372,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.menuview_zoom_out = self.menuview.addAction(QtGui.QIcon('share/zoom_out32.png'), _("&Zoom Out\t-"))
|
||||
self.menuview.addSeparator()
|
||||
|
||||
# Replot all
|
||||
self.menuview_replot = self.menuview.addAction(QtGui.QIcon('share/replot32.png'), _("Redraw All\tF5"))
|
||||
self.menuview.addSeparator()
|
||||
|
||||
self.menuview_toggle_code_editor = self.menuview.addAction(QtGui.QIcon('share/code_editor32.png'),
|
||||
_('Toggle Code Editor\tCTRL+E'))
|
||||
self.menuview.addSeparator()
|
||||
|
@ -5168,15 +5172,16 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
self.excellon_general_label = QtWidgets.QLabel("<b>%s:</b>" % _("Excellon Optimization"))
|
||||
grid2.addWidget(self.excellon_general_label, 4, 0, 1, 2)
|
||||
|
||||
self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm: '))
|
||||
self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm:'))
|
||||
self.excellon_optimization_label.setToolTip(
|
||||
_("This sets the optimization type for the Excellon drill path.\n"
|
||||
"If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
|
||||
"If <<MetaHeuristic>> is checked then Google OR-Tools algorithm with MetaHeuristic\n"
|
||||
"Guided Local Path is used. Default search time is 3sec.\n"
|
||||
"Use set_sys excellon_search_time value Tcl Command to set other values.\n"
|
||||
"If Basic is checked then Google OR-Tools Basic algorithm is used.\n"
|
||||
"If <<Basic>> is checked then Google OR-Tools Basic algorithm is used.\n"
|
||||
"If <<TSA>> is checked then Travelling Salesman algorithm is used for\n"
|
||||
"drill path optimization.\n"
|
||||
"\n"
|
||||
"If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
|
||||
"If this control is disabled, then FlatCAM works in 32bit mode and it uses\n"
|
||||
"Travelling Salesman algorithm for path optimization.")
|
||||
)
|
||||
grid2.addWidget(self.excellon_optimization_label, 5, 0)
|
||||
|
@ -5187,12 +5192,13 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
orientation='vertical', stretch=False)
|
||||
self.excellon_optimization_radio.setToolTip(
|
||||
_("This sets the optimization type for the Excellon drill path.\n"
|
||||
"If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
|
||||
"If <<MetaHeuristic>> is checked then Google OR-Tools algorithm with MetaHeuristic\n"
|
||||
"Guided Local Path is used. Default search time is 3sec.\n"
|
||||
"Use set_sys excellon_search_time value Tcl Command to set other values.\n"
|
||||
"If Basic is checked then Google OR-Tools Basic algorithm is used.\n"
|
||||
"If <<Basic>> is checked then Google OR-Tools Basic algorithm is used.\n"
|
||||
"If <<TSA>> is checked then Travelling Salesman algorithm is used for\n"
|
||||
"drill path optimization.\n"
|
||||
"\n"
|
||||
"If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
|
||||
"If this control is disabled, then FlatCAM works in 32bit mode and it uses\n"
|
||||
"Travelling Salesman algorithm for path optimization.")
|
||||
)
|
||||
grid2.addWidget(self.excellon_optimization_radio, 5, 1)
|
||||
|
|
|
@ -12,6 +12,7 @@ from PyQt5.QtGui import QTextCursor
|
|||
from PyQt5.QtWidgets import QVBoxLayout, QWidget
|
||||
from flatcamGUI.GUIElements import _BrowserTextEdit, _ExpandableTextEdit
|
||||
import html
|
||||
import sys
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -132,6 +133,12 @@ class TermWidget(QWidget):
|
|||
Re-implement in the child classes to actually execute command
|
||||
"""
|
||||
text = str(self._edit.toPlainText())
|
||||
|
||||
# in Windows replace all backslash symbols '\' with '\\' slash because Windows paths are made with backslash
|
||||
# and in Python single slash is the escape symbol
|
||||
if sys.platform == 'win32':
|
||||
text = text.replace('\\', '\\\\')
|
||||
|
||||
self._append_to_browser('in', '> ' + text + '\n')
|
||||
|
||||
if len(self._history) < 2 or self._history[-2] != text: # don't insert duplicating items
|
||||
|
|
|
@ -112,32 +112,37 @@ class TclCommandCncjob(TclCommandSignaled):
|
|||
else:
|
||||
return
|
||||
|
||||
args["dia"] = args["dia"] if "dia" in args else obj.options["cnctooldia"]
|
||||
args["dia"] = args["dia"] if "dia" in args and args["dia"] else obj.options["cnctooldia"]
|
||||
|
||||
args["z_cut"] = args["z_cut"] if "z_cut" in args else obj.options["cutz"]
|
||||
args["z_move"] = args["z_move"] if "z_move" in args else obj.options["travelz"]
|
||||
args["z_cut"] = args["z_cut"] if "z_cut" in args and args["z_cut"] else obj.options["cutz"]
|
||||
args["z_move"] = args["z_move"] if "z_move" in args and args["z_move"] else obj.options["travelz"]
|
||||
|
||||
args["feedrate"] = args["feedrate"] if "feedrate" in args else obj.options["feedrate"]
|
||||
args["feedrate_z"] = args["feedrate_z"] if "feedrate_z" in args else obj.options["feedrate_z"]
|
||||
args["feedrate_rapid"] = args["feedrate_rapid"] if "feedrate_rapid" in args else obj.options["feedrate_rapid"]
|
||||
args["feedrate"] = args["feedrate"] if "feedrate" in args and args["feedrate"] else obj.options["feedrate"]
|
||||
args["feedrate_z"] = args["feedrate_z"] if "feedrate_z" in args and args["feedrate_z"] else \
|
||||
obj.options["feedrate_z"]
|
||||
args["feedrate_rapid"] = args["feedrate_rapid"] if "feedrate_rapid" in args and args["feedrate_rapid"] else \
|
||||
obj.options["feedrate_rapid"]
|
||||
|
||||
args["multidepth"] = args["multidepth"] if "multidepth" in args else obj.options["multidepth"]
|
||||
args["extracut"] = args["extracut"] if "extracut" in args else obj.options["extracut"]
|
||||
args["depthperpass"] = args["depthperpass"] if "depthperpass" in args else obj.options["depthperpass"]
|
||||
args["multidepth"] = args["multidepth"] if "multidepth" in args and args["multidepth"] else \
|
||||
obj.options["multidepth"]
|
||||
args["extracut"] = args["extracut"] if "extracut" in args and args["extracut"] else obj.options["extracut"]
|
||||
args["depthperpass"] = args["depthperpass"] if "depthperpass" in args and args["depthperpass"] else \
|
||||
obj.options["depthperpass"]
|
||||
|
||||
args["startz"] = args["startz"] if "startz" in args else \
|
||||
args["startz"] = args["startz"] if "startz" in args and args["startz"] else \
|
||||
self.app.defaults["geometry_startz"]
|
||||
args["endz"] = args["endz"] if "endz" in args else obj.options["endz"]
|
||||
args["endz"] = args["endz"] if "endz" in args and args["endz"] else obj.options["endz"]
|
||||
|
||||
args["spindlespeed"] = args["spindlespeed"] if "spindlespeed" in args else None
|
||||
args["dwell"] = args["dwell"] if "dwell" in args else obj.options["dwell"]
|
||||
args["dwelltime"] = args["dwelltime"] if "dwelltime" in args else obj.options["dwelltime"]
|
||||
args["spindlespeed"] = args["spindlespeed"] if "spindlespeed" in args and args["spindlespeed"] else None
|
||||
args["dwell"] = args["dwell"] if "dwell" in args and args["dwell"] else obj.options["dwell"]
|
||||
args["dwelltime"] = args["dwelltime"] if "dwelltime" in args and args["dwelltime"] else obj.options["dwelltime"]
|
||||
|
||||
args["pp"] = args["pp"] if "pp" in args else obj.options["ppname_g"]
|
||||
args["pp"] = args["pp"] if "pp" in args and args["pp"] else obj.options["ppname_g"]
|
||||
|
||||
args["toolchange"] = True if "toolchange" in args and args["toolchange"] == 1 else False
|
||||
args["toolchangez"] = args["toolchangez"] if "toolchangez" in args else obj.options["toolchangez"]
|
||||
args["toolchangexy"] = args["toolchangexy"] if "toolchangexy" in args else \
|
||||
args["toolchangez"] = args["toolchangez"] if "toolchangez" in args and args["toolchangez"] else \
|
||||
obj.options["toolchangez"]
|
||||
args["toolchangexy"] = args["toolchangexy"] if "toolchangexy" in args and args["toolchangexy"] else \
|
||||
self.app.defaults["geometry_toolchangexy"]
|
||||
|
||||
del args['name']
|
||||
|
|
|
@ -158,19 +158,20 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
|||
tools = 'all'
|
||||
self.raise_tcl_error("Bad tools: %s" % str(e))
|
||||
|
||||
drillz = args["drillz"] if "drillz" in args else obj.options["drillz"]
|
||||
toolchangez = args["toolchangez"] if "toolchangez" in args else obj.options["toolchangez"]
|
||||
endz = args["endz"] if "endz" in args else obj.options["endz"]
|
||||
drillz = args["drillz"] if "drillz" in args and args["drillz"] else obj.options["drillz"]
|
||||
toolchangez = args["toolchangez"] if "toolchangez" in args and args["toolchangez"] else \
|
||||
obj.options["toolchangez"]
|
||||
endz = args["endz"] if "endz" in args and args["endz"] else obj.options["endz"]
|
||||
toolchange = True if "toolchange" in args and args["toolchange"] == 1 else False
|
||||
opt_type = args["opt_type"] if "opt_type" in args else 'B'
|
||||
opt_type = args["opt_type"] if "opt_type" in args and args["opt_type"] else 'B'
|
||||
|
||||
job_obj.z_move = args["travelz"] if "travelz" in args else obj.options["travelz"]
|
||||
job_obj.feedrate = args["feedrate"] if "feedrate" in args else obj.options["feedrate"]
|
||||
job_obj.z_move = args["travelz"] if "travelz" in args and args["travelz"] else obj.options["travelz"]
|
||||
job_obj.feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else obj.options["feedrate"]
|
||||
job_obj.feedrate_rapid = args["feedrate_rapid"] \
|
||||
if "feedrate_rapid" in args else obj.options["feedrate_rapid"]
|
||||
if "feedrate_rapid" in args and args["feedrate_rapid"] else obj.options["feedrate_rapid"]
|
||||
|
||||
job_obj.spindlespeed = args["spindlespeed"] if "spindlespeed" in args else None
|
||||
job_obj.pp_excellon_name = args["pp"] if "pp" in args \
|
||||
job_obj.pp_excellon_name = args["pp"] if "pp" in args and args["pp"] \
|
||||
else obj.options["ppname_e"]
|
||||
|
||||
job_obj.coords_decimals = int(self.app.defaults["cncjob_coords_decimals"])
|
||||
|
@ -178,7 +179,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
|||
|
||||
job_obj.options['type'] = 'Excellon'
|
||||
|
||||
job_obj.toolchangexy = args["toolchangexy"] if "toolchangexy" in args else obj.options["toolchangexy"]
|
||||
job_obj.toolchangexy = args["toolchangexy"] if "toolchangexy" in args and args["toolchangexy"] else \
|
||||
obj.options["toolchangexy"]
|
||||
|
||||
job_obj.toolchange_xy_type = "excellon"
|
||||
|
||||
|
|
Loading…
Reference in New Issue