- updated the camlib.CNCJob.scale() function so now the GCode is scaled also (quite a HACK :( it will need to be replaced at some point)). Units change work now on the GCODE also.

This commit is contained in:
Marius Stanciu 2019-01-31 23:07:53 +02:00 committed by Marius S
parent 093f210c25
commit d5853722c3
4 changed files with 248 additions and 46 deletions

View File

@ -2652,9 +2652,9 @@ class App(QtCore.QObject):
'excellon_travelz', 'excellon_feedrate', 'excellon_feedrate_rapid', 'excellon_toolchangez', 'excellon_travelz', 'excellon_feedrate', 'excellon_feedrate_rapid', 'excellon_toolchangez',
'excellon_tooldia', 'excellon_endz', 'cncjob_tooldia', 'excellon_tooldia', 'excellon_endz', 'cncjob_tooldia',
'geometry_cutz', 'geometry_travelz', 'geometry_feedrate', 'geometry_feedrate_rapid', 'geometry_cutz', 'geometry_travelz', 'geometry_feedrate', 'geometry_feedrate_rapid',
'geometry_cnctooldia', 'geometry_painttooldia', 'geometry_paintoverlap', 'geometry_toolchangexy', 'geometry_cnctooldia', 'tools_painttooldia', 'tools_paintoverlap', 'geometry_toolchangexy',
'geometry_toolchangez', 'geometry_toolchangez',
'geometry_paintmargin', 'geometry_endz', 'geometry_depthperpass', 'global_gridx', 'global_gridy'] 'tools_paintmargin', 'geometry_endz', 'geometry_depthperpass', 'global_gridx', 'global_gridy']
def scale_options(sfactor): def scale_options(sfactor):
for dim in dimensions: for dim in dimensions:

View File

@ -9,7 +9,7 @@
from io import StringIO from io import StringIO
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from copy import copy, deepcopy import copy
import inspect # TODO: For debugging only. import inspect # TODO: For debugging only.
from shapely.geometry.base import JOIN_STYLE from shapely.geometry.base import JOIN_STYLE
from datetime import datetime from datetime import datetime
@ -165,7 +165,7 @@ class FlatCAMObj(QtCore.QObject):
self.muted_ui = False self.muted_ui = False
def on_name_activate(self): def on_name_activate(self):
old_name = copy(self.options["name"]) old_name = copy.copy(self.options["name"])
new_name = self.ui.name_entry.get_value() new_name = self.ui.name_entry.get_value()
# update the SHELL auto-completer model data # update the SHELL auto-completer model data
@ -1870,7 +1870,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if not isinstance(geo, FlatCAMGerber) and not isinstance(geo, FlatCAMExcellon): if not isinstance(geo, FlatCAMGerber) and not isinstance(geo, FlatCAMExcellon):
for tool_uid in geo.tools: for tool_uid in geo.tools:
max_uid += 1 max_uid += 1
geo_final.tools[max_uid] = dict(geo.tools[tool_uid]) geo_final.tools[max_uid] = copy.deepcopy(geo.tools[tool_uid])
@staticmethod @staticmethod
def get_pts(o): def get_pts(o):
@ -2208,7 +2208,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'type': 'Rough', 'type': 'Rough',
'tool_type': 'C1', 'tool_type': 'C1',
'data': self.default_data, 'data': self.default_data,
'solid_geometry': [] 'solid_geometry': self.solid_geometry
} }
}) })
else: else:
@ -2220,12 +2220,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
temp_tools = {} temp_tools = {}
new_key = 0.0 new_key = 0.0
for tooluid_key in self.tools: for tooluid_key in self.tools:
val = dict(self.tools[tooluid_key]) val = copy.deepcopy(self.tools[tooluid_key])
new_key = deepcopy(int(tooluid_key)) new_key = copy.deepcopy(int(tooluid_key))
temp_tools[new_key] = val temp_tools[new_key] = val
self.tools.clear() self.tools.clear()
self.tools = dict(temp_tools) self.tools = copy.deepcopy(temp_tools)
self.ui.tool_offset_entry.hide() self.ui.tool_offset_entry.hide()
self.ui.tool_offset_lbl.hide() self.ui.tool_offset_lbl.hide()
@ -2435,8 +2435,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Rough', 'type': 'Rough',
'tool_type': 'C1', 'tool_type': 'C1',
'data': dict(self.default_data), 'data': copy.deepcopy(self.default_data),
'solid_geometry': [] 'solid_geometry': self.solid_geometry
} }
}) })
else: else:
@ -2448,6 +2448,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
last_tool_type = self.tools[max_uid]['tool_type'] last_tool_type = self.tools[max_uid]['tool_type']
last_solid_geometry = self.tools[max_uid]['solid_geometry'] last_solid_geometry = self.tools[max_uid]['solid_geometry']
# if previous geometry was empty (it may happen for the first tool added)
# then copy the object.solid_geometry
if not last_solid_geometry:
last_solid_geometry = self.solid_geometry
self.tools.update({ self.tools.update({
self.tooluid: { self.tooluid: {
'tooldia': tooldia, 'tooldia': tooldia,
@ -2455,8 +2460,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'offset_value': last_offset_value, 'offset_value': last_offset_value,
'type': last_type, 'type': last_type,
'tool_type': last_tool_type, 'tool_type': last_tool_type,
'data': dict(last_data), 'data': copy.deepcopy(last_data),
'solid_geometry': deepcopy(last_solid_geometry) 'solid_geometry': copy.deepcopy(last_solid_geometry)
} }
}) })
# print("CURRENT", self.tools[-1]) # print("CURRENT", self.tools[-1])
@ -2497,7 +2502,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
tooluid_copy = int(self.ui.geo_tools_table.item(current_row.row(), 5).text()) tooluid_copy = int(self.ui.geo_tools_table.item(current_row.row(), 5).text())
self.set_tool_offset_visibility(current_row.row()) self.set_tool_offset_visibility(current_row.row())
max_uid += 1 max_uid += 1
self.tools[int(max_uid)] = dict(self.tools[tooluid_copy]) self.tools[int(max_uid)] = copy.deepcopy(self.tools[tooluid_copy])
except AttributeError: except AttributeError:
self.app.inform.emit("[warning_notcl]Failed. Select a tool to copy.") self.app.inform.emit("[warning_notcl]Failed. Select a tool to copy.")
self.build_ui() self.build_ui()
@ -2513,10 +2518,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
else: else:
# we copy all tools in geo_tools_table # we copy all tools in geo_tools_table
try: try:
temp_tools = dict(self.tools) temp_tools = copy.deepcopy(self.tools)
max_uid += 1 max_uid += 1
for tooluid in temp_tools: for tooluid in temp_tools:
self.tools[int(max_uid)] = dict(temp_tools[tooluid]) self.tools[int(max_uid)] = copy.deepcopy(temp_tools[tooluid])
temp_tools.clear() temp_tools.clear()
except Exception as e: except Exception as e:
log.debug("on_tool_copy() --> " + str(e)) log.debug("on_tool_copy() --> " + str(e))
@ -2570,11 +2575,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
tooluid_del = int(self.ui.geo_tools_table.item(current_row.row(), 5).text()) tooluid_del = int(self.ui.geo_tools_table.item(current_row.row(), 5).text())
self.set_tool_offset_visibility(current_row.row()) self.set_tool_offset_visibility(current_row.row())
temp_tools = dict(self.tools) temp_tools = copy.deepcopy(self.tools)
for tooluid_key in self.tools: for tooluid_key in self.tools:
if int(tooluid_key) == tooluid_del: if int(tooluid_key) == tooluid_del:
temp_tools.pop(tooluid_del, None) temp_tools.pop(tooluid_del, None)
self.tools = dict(temp_tools) self.tools = copy.deepcopy(temp_tools)
temp_tools.clear() temp_tools.clear()
except AttributeError: except AttributeError:
self.app.inform.emit("[warning_notcl]Failed. Select a tool to delete.") self.app.inform.emit("[warning_notcl]Failed. Select a tool to delete.")
@ -2840,19 +2845,19 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# updated from self.app.defaults # updated from self.app.defaults
if data_key not in self.form_fields: if data_key not in self.form_fields:
temp_data[data_key] = value[data_key] temp_data[data_key] = value[data_key]
temp_dia[key] = dict(temp_data) temp_dia[key] = copy.deepcopy(temp_data)
temp_data.clear() temp_data.clear()
if key == 'solid_geometry': if key == 'solid_geometry':
temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry']) temp_dia[key] = copy.deepcopy(self.tools[tooluid_key]['solid_geometry'])
temp_tools[tooluid_key] = dict(temp_dia) temp_tools[tooluid_key] = copy.deepcopy(temp_dia)
else: else:
temp_tools[tooluid_key] = dict(tooluid_value) temp_tools[tooluid_key] = copy.deepcopy(tooluid_value)
self.tools.clear() self.tools.clear()
self.tools = dict(temp_tools) self.tools = copy.deepcopy(temp_tools)
temp_tools.clear() temp_tools.clear()
self.ui_connect() self.ui_connect()
@ -2957,7 +2962,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
for tooluid_key, tooluid_value in self.tools.items(): for tooluid_key, tooluid_value in self.tools.items():
if int(tooluid_key) == tooluid: if int(tooluid_key) == tooluid:
self.sel_tools.update({ self.sel_tools.update({
tooluid: dict(tooluid_value) tooluid: copy.deepcopy(tooluid_value)
}) })
self.mtool_gen_cncjob() self.mtool_gen_cncjob()
@ -3084,7 +3089,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if data_key == "dwelltime": if data_key == "dwelltime":
dwelltime = data_value dwelltime = data_value
datadict = dict(diadict_value) datadict = copy.deepcopy(diadict_value)
dia_cnc_dict.update({ dia_cnc_dict.update({
diadict_key: datadict diadict_key: datadict
}) })
@ -3153,7 +3158,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
app_obj.progress.emit(80) app_obj.progress.emit(80)
job_obj.cnc_tools.update({ job_obj.cnc_tools.update({
tooluid_key: dict(dia_cnc_dict) tooluid_key: copy.deepcopy(dia_cnc_dict)
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
@ -3256,7 +3261,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
if data_key == "dwelltime": if data_key == "dwelltime":
dwelltime = data_value dwelltime = data_value
datadict = dict(diadict_value) datadict = copy.deepcopy(diadict_value)
dia_cnc_dict.update({ dia_cnc_dict.update({
diadict_key: datadict diadict_key: datadict
}) })
@ -3325,7 +3330,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
app_obj.progress.emit(80) app_obj.progress.emit(80)
job_obj.cnc_tools.update({ job_obj.cnc_tools.update({
tooluid_key: dict(dia_cnc_dict) tooluid_key: copy.deepcopy(dia_cnc_dict)
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
@ -3584,9 +3589,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.options['feedrate_rapid'] *= factor self.options['feedrate_rapid'] *= factor
self.options['endz'] *= factor self.options['endz'] *= factor
# self.options['cnctooldia'] *= factor # self.options['cnctooldia'] *= factor
self.options['painttooldia'] *= factor # self.options['painttooldia'] *= factor
self.options['paintmargin'] *= factor # self.options['paintmargin'] *= factor
self.options['paintoverlap'] *= factor # self.options['paintoverlap'] *= factor
self.options["toolchangez"] *= factor self.options["toolchangez"] *= factor
@ -3642,17 +3647,17 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# copy the other dict entries that are not convertible # copy the other dict entries that are not convertible
if data_key not in param_list: if data_key not in param_list:
data_copy[data_key] = data_value data_copy[data_key] = data_value
tool_dia_copy[dia_key] = dict(data_copy) tool_dia_copy[dia_key] = copy.deepcopy(data_copy)
data_copy.clear() data_copy.clear()
temp_tools_dict.update({ temp_tools_dict.update({
tooluid_key: dict(tool_dia_copy) tooluid_key: copy.deepcopy(tool_dia_copy)
}) })
tool_dia_copy.clear() tool_dia_copy.clear()
self.tools.clear() self.tools.clear()
self.tools = dict(temp_tools_dict) self.tools = copy.deepcopy(temp_tools_dict)
# if there is a value in the new tool field then convert that one too # if there is a value in the new tool field then convert that one too
tooldia = self.ui.addtool_entry.get_value() tooldia = self.ui.addtool_entry.get_value()
@ -3817,11 +3822,22 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
# (like the one in the TCL Command), False # (like the one in the TCL Command), False
self.multitool = False self.multitool = False
# used for parsing the GCode lines to adjust the offset when the GCode was offseted # used for parsing the GCode lines to adjust the GCode when the GCode is offseted or scaled
offsetx_re_string = r'(?=.*(X[-\+]?\d*\.\d*))' gcodex_re_string = r'(?=.*(X[-\+]?\d*\.\d*))'
self.g_offsetx_re = re.compile(offsetx_re_string) self.g_x_re = re.compile(gcodex_re_string)
offsety_re_string = r'(?=.*(Y[-\+]?\d*\.\d*))' gcodey_re_string = r'(?=.*(Y[-\+]?\d*\.\d*))'
self.g_offsety_re = re.compile(offsety_re_string) self.g_y_re = re.compile(gcodey_re_string)
gcodez_re_string = r'(?=.*(Z[-\+]?\d*\.\d*))'
self.g_z_re = re.compile(gcodez_re_string)
gcodef_re_string = r'(?=.*(F[-\+]?\d*\.\d*))'
self.g_f_re = re.compile(gcodef_re_string)
gcodet_re_string = r'(?=.*(\=\s*[-\+]?\d*\.\d*))'
self.g_t_re = re.compile(gcodet_re_string)
gcodenr_re_string = r'([+-]?\d*\.\d*)'
self.g_nr_re = re.compile(gcodenr_re_string)
# Attributes to be included in serialization # Attributes to be included in serialization
# Always append to it because it carries contents # Always append to it because it carries contents
# from predecessors. # from predecessors.
@ -4272,4 +4288,63 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()") FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()")
self.options["tooldia"] *= factor self.options["tooldia"] *= factor
param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid',
'endz', 'toolchangez']
temp_tools_dict = {}
tool_dia_copy = {}
data_copy = {}
for tooluid_key, tooluid_value in self.cnc_tools.items():
for dia_key, dia_value in tooluid_value.items():
if dia_key == 'tooldia':
dia_value *= factor
dia_value = float('%.4f' % dia_value)
tool_dia_copy[dia_key] = dia_value
if dia_key == 'offset':
tool_dia_copy[dia_key] = dia_value
if dia_key == 'offset_value':
dia_value *= factor
tool_dia_copy[dia_key] = dia_value
if dia_key == 'type':
tool_dia_copy[dia_key] = dia_value
if dia_key == 'tool_type':
tool_dia_copy[dia_key] = dia_value
if dia_key == 'data':
for data_key, data_value in dia_value.items():
# convert the form fields that are convertible
for param in param_list:
if data_key == param and data_value is not None:
data_copy[data_key] = data_value * factor
# copy the other dict entries that are not convertible
if data_key not in param_list:
data_copy[data_key] = data_value
tool_dia_copy[dia_key] = copy.deepcopy(data_copy)
data_copy.clear()
if dia_key == 'gcode':
tool_dia_copy[dia_key] = dia_value
if dia_key == 'gcode_parsed':
tool_dia_copy[dia_key] = dia_value
if dia_key == 'solid_geometry':
tool_dia_copy[dia_key] = dia_value
# if dia_key == 'solid_geometry':
# tool_dia_copy[dia_key] = affinity.scale(dia_value, xfact=factor, origin=(0, 0))
# if dia_key == 'gcode_parsed':
# for g in dia_value:
# g['geom'] = affinity.scale(g['geom'], factor, factor, origin=(0, 0))
#
# tool_dia_copy['gcode_parsed'] = copy.deepcopy(dia_value)
# tool_dia_copy['solid_geometry'] = cascaded_union([geo['geom'] for geo in dia_value])
temp_tools_dict.update({
tooluid_key: copy.deepcopy(tool_dia_copy)
})
tool_dia_copy.clear()
self.cnc_tools.clear()
self.cnc_tools = copy.deepcopy(temp_tools_dict)
# end of file # end of file

View File

@ -15,6 +15,7 @@ CAD program, and create G-Code for Isolation routing.
- added new function to toggle fullscreen status in Menu -> View -> Toggle Full Screen. Shortcut key: Alt+F10 - added new function to toggle fullscreen status in Menu -> View -> Toggle Full Screen. Shortcut key: Alt+F10
- added key shortcuts for Enable Plots, Disable Plots and Disable other plots functions (Alt+1, Alt+2, Alt+3) - added key shortcuts for Enable Plots, Disable Plots and Disable other plots functions (Alt+1, Alt+2, Alt+3)
- hidden the snap magnet entry and snap magnet toggle from the main view; they are now active only in Editor Mode - hidden the snap magnet entry and snap magnet toggle from the main view; they are now active only in Editor Mode
- updated the camlib.CNCJob.scale() function so now the GCode is scaled also (quite a HACK :( it will need to be replaced at some point)). Units change work now on the GCODE also.
30.01.2019 30.01.2019

140
camlib.py
View File

@ -5869,6 +5869,7 @@ class CNCjob(Geometry):
else: else:
# it's a Shapely object, return it's bounds # it's a Shapely object, return it's bounds
return obj.bounds return obj.bounds
if self.multitool is False: if self.multitool is False:
log.debug("CNCJob->bounds()") log.debug("CNCJob->bounds()")
if self.solid_geometry is None: if self.solid_geometry is None:
@ -5877,21 +5878,30 @@ class CNCjob(Geometry):
bounds_coords = bounds_rec(self.solid_geometry) bounds_coords = bounds_rec(self.solid_geometry)
else: else:
for k, v in self.cnc_tools.items(): for k, v in self.cnc_tools.items():
minx = Inf minx = Inf
miny = Inf miny = Inf
maxx = -Inf maxx = -Inf
maxy = -Inf maxy = -Inf
try:
for k in v['solid_geometry']: for k in v['solid_geometry']:
minx_, miny_, maxx_, maxy_ = bounds_rec(k) minx_, miny_, maxx_, maxy_ = bounds_rec(k)
minx = min(minx, minx_)
miny = min(miny, miny_)
maxx = max(maxx, maxx_)
maxy = max(maxy, maxy_)
except TypeError:
minx_, miny_, maxx_, maxy_ = bounds_rec(v['solid_geometry'])
minx = min(minx, minx_) minx = min(minx, minx_)
miny = min(miny, miny_) miny = min(miny, miny_)
maxx = max(maxx, maxx_) maxx = max(maxx, maxx_)
maxy = max(maxy, maxy_) maxy = max(maxy, maxy_)
bounds_coords = minx, miny, maxx, maxy bounds_coords = minx, miny, maxx, maxy
return bounds_coords return bounds_coords
# TODO This function should be replaced at some point with a "real" function. Until then it's an ugly hack ...
def scale(self, xfactor, yfactor=None, point=None): def scale(self, xfactor, yfactor=None, point=None):
""" """
Scales all the geometry on the XY plane in the object by the Scales all the geometry on the XY plane in the object by the
@ -5915,8 +5925,124 @@ class CNCjob(Geometry):
else: else:
px, py = point px, py = point
for g in self.gcode_parsed: def scale_g(g):
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py)) """
:param g: 'g' parameter it's a gcode string
:return: scaled gcode string
"""
temp_gcode = ''
header_start = False
header_stop = False
units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
lines = StringIO(g)
for line in lines:
# this changes the GCODE header ---- UGLY HACK
if "TOOL DIAMETER" in line or "Feedrate:" in line:
header_start = True
if "G20" in line or "G21" in line:
header_start = False
header_stop = True
if header_start is True:
header_stop = False
if "in" in line:
if units == 'MM':
line = line.replace("in", "mm")
if "mm" in line:
if units == 'IN':
line = line.replace("mm", "in")
# find any number in header and convert it
match_nr = self.g_nr_re.search(line)
if match_nr:
new_nr = float(match_nr.group()) * xfactor
# replace the updated string
line = line.replace(match_nr.group(),
('%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_nr))
)
# this scales all the X and Y and Z and F values and also the Tool Dia in the toolchange message
if header_stop is True:
if "G20" in line:
if units == 'MM':
line = line.replace("G20", "G21")
if "G21" in line:
if units == 'IN':
line = line.replace("G21", "G20")
# find the X group
match_x = self.g_x_re.search(line)
if match_x:
if match_x.group(1) is not None:
new_x = float(match_x.group(1)[1:]) * xfactor
# replace the updated string
line = line.replace(
match_x.group(1),
'X%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_x)
)
# find the Y group
match_y = self.g_y_re.search(line)
if match_y:
if match_y.group(1) is not None:
new_y = float(match_y.group(1)[1:]) * yfactor
line = line.replace(
match_y.group(1),
'Y%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_y)
)
# find the Z group
match_z = self.g_z_re.search(line)
if match_z:
if match_z.group(1) is not None:
new_z = float(match_z.group(1)[1:]) * xfactor
line = line.replace(
match_z.group(1),
'Z%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_z)
)
# find the F group
match_f = self.g_f_re.search(line)
if match_f:
if match_f.group(1) is not None:
new_f = float(match_f.group(1)[1:]) * xfactor
line = line.replace(
match_f.group(1),
'F%.*f' % (self.app.defaults["cncjob_fr_decimals"], new_f)
)
# find the T group (tool dia on toolchange)
match_t = self.g_t_re.search(line)
if match_t:
if match_t.group(1) is not None:
new_t = float(match_t.group(1)[1:]) * xfactor
line = line.replace(
match_t.group(1),
'= %.*f' % (self.app.defaults["cncjob_coords_decimals"], new_t)
)
temp_gcode += line
lines.close()
header_stop = False
return temp_gcode
if self.multitool is False:
# offset Gcode
self.gcode = scale_g(self.gcode)
# offset geometry
for g in self.gcode_parsed:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
self.create_geometry()
else:
for k, v in self.cnc_tools.items():
# scale Gcode
v['gcode'] = scale_g(v['gcode'])
# scale gcode_parsed
for g in v['gcode_parsed']:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
v['solid_geometry'] = cascaded_union([geo['geom'] for geo in v['gcode_parsed']])
self.create_geometry() self.create_geometry()
@ -5946,7 +6072,7 @@ class CNCjob(Geometry):
lines = StringIO(g) lines = StringIO(g)
for line in lines: for line in lines:
# find the X group # find the X group
match_x = self.g_offsetx_re.search(line) match_x = self.g_x_re.search(line)
if match_x: if match_x:
if match_x.group(1) is not None: if match_x.group(1) is not None:
# get the coordinate and add X offset # get the coordinate and add X offset
@ -5956,7 +6082,7 @@ class CNCjob(Geometry):
match_x.group(1), match_x.group(1),
'X%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_x) 'X%.*f' % (self.app.defaults["cncjob_coords_decimals"], new_x)
) )
match_y = self.g_offsety_re.search(line) match_y = self.g_y_re.search(line)
if match_y: if match_y:
if match_y.group(1) is not None: if match_y.group(1) is not None:
new_y = float(match_y.group(1)[1:]) + dy new_y = float(match_y.group(1)[1:]) + dy