- remade the Excellon export function to work with parameters entered in Edit -> Preferences -> Excellon Export

- added a new entry in the Project Context Menu named 'Save'. It will actually work for Geometry and it will do Export DXF and for Excellon and it will do Export Excellon
This commit is contained in:
Marius Stanciu 2019-02-15 23:35:23 +02:00 committed by Marius S
parent aea67a4a1d
commit e717cb8f15
5 changed files with 195 additions and 157 deletions

View File

@ -1079,8 +1079,8 @@ class App(QtCore.QObject):
self.ui.menufileexportsvg.triggered.connect(self.on_file_exportsvg)
self.ui.menufileexportpng.triggered.connect(self.on_file_exportpng)
self.ui.menufileexportexcellon.triggered.connect(lambda: self.on_file_exportexcellon(altium_format=None))
self.ui.menufileexportexcellon_altium.triggered.connect(lambda: self.on_file_exportexcellon(altium_format=True))
self.ui.menufileexportexcellon.triggered.connect(self.on_file_exportexcellon)
self.ui.menufileexportdxf.triggered.connect(self.on_file_exportdxf)
@ -1156,6 +1156,7 @@ class App(QtCore.QObject):
self.ui.menuprojectedit.triggered.connect(self.object2editor)
self.ui.menuprojectdelete.triggered.connect(self.on_delete)
self.ui.menuprojectsave.triggered.connect(self.on_project_context_save)
self.ui.menuprojectproperties.triggered.connect(self.obj_properties)
# Toolbar
@ -4693,6 +4694,13 @@ class App(QtCore.QObject):
self.properties_tool.run()
def on_project_context_save(self):
obj = self.collection.get_active()
if type(obj) == FlatCAMGeometry:
self.on_file_exportdxf()
elif type(obj) == FlatCAMExcellon:
self.on_file_exportexcellon()
def obj_move(self):
self.report_usage("obj_move()")
@ -4939,7 +4947,7 @@ class App(QtCore.QObject):
write_png(filename, data)
self.file_saved.emit("png", filename)
def on_file_exportexcellon(self, altium_format=None):
def on_file_exportexcellon(self):
"""
Callback for menu item File->Export SVG.
@ -4971,7 +4979,7 @@ class App(QtCore.QObject):
name = self.collection.get_active().options["name"]
filter = "Excellon File (*.drl);;Excellon File (*.txt);;All Files (*.*)"
filter = "Excellon File (*.DRL);;Excellon File (*.TXT);;All Files (*.*)"
try:
filename, _ = QtWidgets.QFileDialog.getSaveFileName(
caption="Export Excellon",
@ -4986,12 +4994,8 @@ class App(QtCore.QObject):
self.inform.emit("[WARNING_NOTCL]Export Excellon cancelled.")
return
else:
if altium_format is None:
self.export_excellon(name, filename)
self.file_saved.emit("Excellon", filename)
else:
self.export_excellon(name, filename, altium_format=True)
self.file_saved.emit("Excellon", filename)
self.export_excellon(name, filename)
self.file_saved.emit("Excellon", filename)
def on_file_exportdxf(self):
"""
@ -5528,9 +5532,17 @@ class App(QtCore.QObject):
return "Could not retrieve object: %s" % obj_name
# updated units
units = self.defaults["excellon_exp_units"]
whole = self.defaults["excellon_exp_integer"]
fract = self.defaults["excellon_exp_decimals"]
eunits = self.defaults["excellon_exp_units"]
ewhole = self.defaults["excellon_exp_integer"]
efract = self.defaults["excellon_exp_decimals"]
ezeros = self.defaults["excellon_exp_zeros"]
eformat = self.defaults[ "excellon_exp_format"]
fc_units = self.general_options_form.general_app_group.units_radio.get_value().upper()
if fc_units == 'MM':
factor = 1 if eunits == 'METRIC' else 0.03937
else:
factor = 25.4 if eunits == 'METRIC' else 1
def make_excellon():
try:
@ -5538,32 +5550,55 @@ class App(QtCore.QObject):
header = 'M48\n'
header += ';EXCELLON GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \
(str(self.app.version), str(self.app.version_date))
(str(self.version), str(self.version_date))
header += ';Filename: %s' % str(obj_name) + '\n'
header += ';Created on : %s' % time_str + '\n'
if self.defaults["excellon_exp_format"] == 'dec':
has_slots, excellon_code = obj.export_excellon_decimals(whole, fract, units)
header += units + '\n'
if eformat == 'dec':
has_slots, excellon_code = obj.export_excellon(ewhole, efract, factor=factor)
header += eunits + '\n'
for tool in obj.tools:
if units == 'METRIC':
header += 'T' + str(tool) + 'F00S00' + 'C' + '%.2f' % float(obj.tools[tool]['C']) + '\n'
if eunits == 'METRIC':
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=2)
else:
header += 'T' + str(tool) + 'F00S00' + 'C' + '%.4f' % float(obj.tools[tool]['C']) + '\n'
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=4)
else:
has_slots, excellon_code = obj.export_excellon_ndecimals(whole, fract, units)
header += '%s,%s\n' % (units, self.defaults["excellon_exp_zeros"])
header += format_exc
if ezeros == 'LZ':
has_slots, excellon_code = obj.export_excellon(ewhole, efract,
form='ndec', e_zeros='LZ', factor=factor)
header += '%s,%s\n' % (eunits, 'LZ')
header += format_exc
for tool in obj.tools:
if units == 'METRIC':
header += 'T' + str(tool) + 'F00S00' + 'C' + \
'%.2f' % (float(obj.tools[tool]['C']) / 25.4) + '\n'
else:
header += 'T' + str(tool) + 'F00S00' + 'C' + '%.4f' % float(obj.tools[tool]['C']) + '\n'
for tool in obj.tools:
if eunits == 'METRIC':
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=2)
else:
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=4)
else:
has_slots, excellon_code = obj.export_excellon(ewhole, efract,
form='ndec', e_zeros='TZ', factor=factor)
header += '%s,%s\n' % (eunits, 'TZ')
header += format_exc
for tool in obj.tools:
if eunits == 'METRIC':
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=2)
else:
header += "T{tool}F00S00C{:.{dec}f}\n".format(float(obj.tools[tool]['C']) * factor,
tool=str(tool),
dec=4)
header += '%\n'
footer = 'M30\n'
@ -5576,7 +5611,8 @@ class App(QtCore.QObject):
self.file_saved.emit("Excellon", filename)
self.inform.emit("[success] Excellon file exported to " + filename)
except:
except Exception as e:
log.debug("App.export_excellon.make_excellon() --> %s" % str(e))
return 'fail'
if use_thread is True:

View File

@ -154,19 +154,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menufileexportexcellon = QtWidgets.QAction(QtGui.QIcon('share/drill32.png'), 'Export &Excellon ...', self)
self.menufileexportexcellon.setToolTip(
"Will export an Excellon Object as Excellon file,\n"
"the coordinates format is decimal and the file units\n"
"are the current units set in FlatCAM."
"the coordinates format, the file units and zeros\n"
"are set in Preferences -> Excellon Export."
)
self.menufileexport.addAction(self.menufileexportexcellon)
self.menufileexportexcellon_altium = QtWidgets.QAction(QtGui.QIcon('share/drill32.png'),
'Export Excellon 2:4 LZ INCH ...', self)
self.menufileexportexcellon_altium.setToolTip(
"Will export an Excellon Object as Excellon file,\n"
"the coordinates format is 2:4, excellon zeros are LZ \n"
"and the file units are INCH."
)
self.menufileexport.addAction(self.menufileexportexcellon_altium)
# Separator
self.menufile.addSeparator()
@ -428,10 +420,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuproject.addSeparator()
self.menuprojectgeneratecnc = self.menuproject.addAction(QtGui.QIcon('share/cnc32.png'), 'Generate CNC')
self.menuproject.addSeparator()
self.menuprojectedit = self.menuproject.addAction(QtGui.QIcon('share/edit_ok32.png'), 'Edit')
self.menuprojectcopy = self.menuproject.addAction(QtGui.QIcon('share/copy32.png'), 'Copy')
self.menuprojectdelete = self.menuproject.addAction(QtGui.QIcon('share/delete32.png'), 'Delete')
self.menuprojectedit = self.menuproject.addAction(QtGui.QIcon('share/edit_ok32.png'), 'Edit')
self.menuprojectsave= self.menuproject.addAction(QtGui.QIcon('share/save_as.png'), 'Save')
self.menuproject.addSeparator()
self.menuprojectproperties = self.menuproject.addAction(QtGui.QIcon('share/properties32.png'), 'Properties')
################

View File

@ -1612,32 +1612,64 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
item[0] = str(item[0])
return table_tools_items
def export_excellon_decimals(self, whole, fract, units):
def export_excellon(self, whole, fract, e_zeros=None, form='dec', factor=1):
"""
Returns two values, first is a boolean , if 1 then the file has slots and second contain the Excellon code
:return: has_slots and Excellon_code
"""
excellon_code = ''
units = units
# store here if the file has slots, return 1 if any slots, 0 if only drills
has_slots = 0
# drills processing
try:
for tool in self.tools:
if int(tool) < 10:
excellon_code += 'T0' + str(tool) + '\n'
else:
excellon_code += 'T' + str(tool) + '\n'
if self.drills:
length = whole + fract
for tool in self.tools:
excellon_code += 'T0%s\n' % str(tool) if int(tool) < 10 else 'T%s\n' % str(tool)
for drill in self.drills:
if tool == drill['tool']:
if units == 'MM':
excellon_code += 'X' + '%.3f' % drill['point'].x + 'Y' + '%.3f' % drill['point'].y + '\n'
else:
excellon_code += 'X' + '%.4f' % drill['point'].x + 'Y' + '%.4f' % drill['point'].y + '\n'
for drill in self.drills:
if form == 'dec' and tool == drill['tool']:
drill_x = drill['point'].x * factor
drill_y = drill['point'].y * factor
excellon_code += "X{:.{dec}f}Y{:.{dec}f}\n".format(drill_x, drill_y, dec=fract)
elif e_zeros == 'LZ' and tool == drill['tool']:
drill_x = drill['point'].x * factor
drill_y = drill['point'].y * factor
exc_x_formatted = "{:.{dec}f}".format(drill_x, dec=fract)
exc_y_formatted = "{:.{dec}f}".format(drill_y, dec=fract)
# extract whole part and decimal part
exc_x_formatted = exc_x_formatted.partition('.')
exc_y_formatted = exc_y_formatted.partition('.')
# left padd the 'whole' part with zeros
x_whole = exc_x_formatted[0].rjust(whole, '0')
y_whole = exc_y_formatted[0].rjust(whole, '0')
# restore the coordinate padded in the left with 0 and added the decimal part
# without the decinal dot
exc_x_formatted = x_whole + exc_x_formatted[2]
exc_y_formatted = y_whole + exc_y_formatted[2]
excellon_code += "X{xform}Y{yform}\n".format(xform=exc_x_formatted,
yform=exc_y_formatted)
elif tool == drill['tool']:
drill_x = drill['point'].x * factor
drill_y = drill['point'].y * factor
exc_x_formatted = "{:.{dec}f}".format(drill_x, dec=fract).replace('.', '')
exc_y_formatted = "{:.{dec}f}".format(drill_y, dec=fract).replace('.', '')
# pad with rear zeros
exc_x_formatted.ljust(length, '0')
exc_y_formatted.ljust(length, '0')
excellon_code += "X{xform}Y{yform}\n".format(xform=exc_x_formatted,
yform=exc_y_formatted)
except Exception as e:
log.debug(str(e))
@ -1652,111 +1684,81 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
excellon_code += 'T' + str(tool) + '\n'
for slot in self.slots:
if tool == slot['tool']:
if units == 'MM':
excellon_code += 'G00' + 'X' + '%.3f' % slot['start'].x + 'Y' + \
'%.3f' % slot['start'].y + '\n'
excellon_code += 'M15\n'
excellon_code += 'G01' + 'X' + '%.3f' % slot['stop'].x + 'Y' + \
'%.3f' % slot['stop'].y + '\n'
excellon_code += 'M16\n'
else:
excellon_code += 'G00' + 'X' + '%.4f' % slot['start'].x + 'Y' + \
'%.4f' % slot['start'].y + '\n'
excellon_code += 'M15\n'
excellon_code += 'G01' + 'X' + '%.4f' % slot['stop'].x + 'Y' + \
'%.4f' % slot['stop'].y + '\n'
excellon_code += 'M16\n'
if form == 'dec' and tool == slot['tool']:
start_slot_x = slot['start'].x * factor
start_slot_y = slot['start'].y * factor
stop_slot_x = slot['stop'].x * factor
stop_slot_y = slot['stop'].y * factor
excellon_code += "G00X{:.{dec}f}Y{:.{dec}f}\nM15\n".format(start_slot_x,
start_slot_y,
dec=fract)
excellon_code += "G00X{:.{dec}f}Y{:.{dec}f}\nM16\n".format(stop_slot_x,
stop_slot_y,
dec=fract)
elif e_zeros == 'LZ' and tool == slot['tool']:
start_slot_x = slot['start'].x * factor
start_slot_y = slot['start'].y * factor
stop_slot_x = slot['stop'].x * factor
stop_slot_y = slot['stop'].y * factor
start_slot_x_formatted = "{:.{dec}f}".format(start_slot_x, dec=fract).replace('.', '')
start_slot_y_formatted = "{:.{dec}f}".format(start_slot_y, dec=fract).replace('.', '')
stop_slot_x_formatted = "{:.{dec}f}".format(stop_slot_x, dec=fract).replace('.', '')
stop_slot_y_formatted = "{:.{dec}f}".format(stop_slot_y, dec=fract).replace('.', '')
# extract whole part and decimal part
start_slot_x_formatted = start_slot_x_formatted.partition('.')
start_slot_y_formatted = start_slot_y_formatted.partition('.')
stop_slot_x_formatted = stop_slot_x_formatted.partition('.')
stop_slot_y_formatted = stop_slot_y_formatted.partition('.')
# left padd the 'whole' part with zeros
start_x_whole = start_slot_x_formatted[0].rjust(whole, '0')
start_y_whole = start_slot_y_formatted[0].rjust(whole, '0')
stop_x_whole = stop_slot_x_formatted[0].rjust(whole, '0')
stop_y_whole = stop_slot_y_formatted[0].rjust(whole, '0')
# restore the coordinate padded in the left with 0 and added the decimal part
# without the decinal dot
start_slot_x_formatted = start_x_whole + start_slot_x_formatted[2]
start_slot_y_formatted = start_y_whole + start_slot_y_formatted[2]
stop_slot_x_formatted = stop_x_whole + stop_slot_x_formatted[2]
stop_slot_y_formatted = stop_y_whole + stop_slot_y_formatted[2]
excellon_code += "G00X{xstart}Y{ystart}\nM15\n".format(xstart=start_slot_x_formatted,
ystart=start_slot_y_formatted)
excellon_code += "G00X{xstop}Y{ystop}\nM16\n".format(xstop=stop_slot_x_formatted,
ystop=stop_slot_y_formatted)
elif tool == slot['tool']:
start_slot_x = slot['start'].x * factor
start_slot_y = slot['start'].y * factor
stop_slot_x = slot['stop'].x * factor
stop_slot_y = slot['stop'].y * factor
length = whole + fract
start_slot_x_formatted = "{:.{dec}f}".format(start_slot_x, dec=fract).replace('.', '')
start_slot_y_formatted = "{:.{dec}f}".format(start_slot_y, dec=fract).replace('.', '')
stop_slot_x_formatted = "{:.{dec}f}".format(stop_slot_x, dec=fract).replace('.', '')
stop_slot_y_formatted = "{:.{dec}f}".format(stop_slot_y, dec=fract).replace('.', '')
# pad with rear zeros
start_slot_x_formatted.ljust(length, '0')
start_slot_y_formatted.ljust(length, '0')
stop_slot_x_formatted.ljust(length, '0')
stop_slot_y_formatted.ljust(length, '0')
excellon_code += "G00X{xstart}Y{ystart}\nM15\n".format(xstart=start_slot_x_formatted,
ystart=start_slot_y_formatted)
excellon_code += "G00X{xstop}Y{ystop}\nM16\n".format(xstop=stop_slot_x_formatted,
ystop=stop_slot_y_formatted)
except Exception as e:
log.debug(str(e))
return has_slots, excellon_code
def export_excellon_ndecimals(self, whole, fract, units):
"""
Returns two values, first is a boolean , if 1 then the file has slots and second contain the Excellon code
:return: has_slots and Excellon_code
"""
excellon_code = ''
units = units
# store here if the file has slots, return 1 if any slots, 0 if only drills
has_slots = 0
# drills processing
try:
for tool in self.tools:
if int(tool) < 10:
excellon_code += 'T0' + str(tool) + '\n'
else:
excellon_code += 'T' + str(tool) + '\n'
for drill in self.drills:
if tool == drill['tool']:
drill_x = drill['point'].x
drill_y = drill['point'].y
if units == 'MM':
drill_x /= 25.4
drill_y /= 25.4
exc_x_formatted = ('%.4f' % drill_x).replace('.', '')
if drill_x < 10:
exc_x_formatted = '0' + exc_x_formatted
exc_y_formatted = ('%.4f' % drill_y).replace('.', '')
if drill_y < 10:
exc_y_formatted = '0' + exc_y_formatted
excellon_code += 'X' + exc_x_formatted + 'Y' + exc_y_formatted + '\n'
except Exception as e:
log.debug(str(e))
# slots processing
try:
if self.slots:
has_slots = 1
for tool in self.tools:
if int(tool) < 10:
excellon_code += 'T0' + str(tool) + '\n'
else:
excellon_code += 'T' + str(tool) + '\n'
for slot in self.slots:
if tool == slot['tool']:
start_slot_x = slot['start'].x
start_slot_y = slot['start'].y
stop_slot_x = slot['stop'].x
stop_slot_y = slot['stop'].y
if units == 'MM':
start_slot_x /= 25.4
start_slot_y /= 25.4
stop_slot_x /= 25.4
stop_slot_y /= 25.4
start_slot_x_formatted = ('%.4f' % start_slot_x).replace('.', '')
if start_slot_x < 10:
start_slot_x_formatted = '0' + start_slot_x_formatted
start_slot_y_formatted = ('%.4f' % start_slot_y).replace('.', '')
if start_slot_y < 10:
start_slot_y_formatted = '0' + start_slot_y_formatted
stop_slot_x_formatted = ('%.4f' % stop_slot_x).replace('.', '')
if stop_slot_x < 10:
stop_slot_x_formatted = '0' + stop_slot_x_formatted
stop_slot_y_formatted = ('%.4f' % stop_slot_y).replace('.', '')
if stop_slot_y < 10:
stop_slot_y_formatted = '0' + stop_slot_y_formatted
excellon_code += 'G00' + 'X' + start_slot_x_formatted + 'Y' + \
start_slot_y_formatted + '\n'
excellon_code += 'M15\n'
excellon_code += 'G01' + 'X' + stop_slot_x_formatted + 'Y' + \
stop_slot_y_formatted + '\n'
excellon_code += 'M16\n'
except Exception as e:
log.debug(str(e))
if not self.drills and not self.slots:
log.debug("FlatCAMObj.FlatCAMExcellon.export_excellon() --> Excellon Object is empty: no drills, no slots.")
return 'fail'
return has_slots, excellon_code

View File

@ -507,17 +507,20 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.ui.menuprojectcopy.setEnabled(sel)
self.app.ui.menuprojectedit.setEnabled(sel)
self.app.ui.menuprojectdelete.setEnabled(sel)
self.app.ui.menuprojectsave.setEnabled(sel)
self.app.ui.menuprojectproperties.setEnabled(sel)
if sel:
self.app.ui.menuprojectgeneratecnc.setVisible(True)
self.app.ui.menuprojectedit.setVisible(True)
self.app.ui.menuprojectsave.setVisible(True)
for obj in self.get_selected():
if type(obj) != FlatCAMGeometry:
self.app.ui.menuprojectgeneratecnc.setVisible(False)
if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon:
self.app.ui.menuprojectedit.setVisible(False)
self.app.ui.menuprojectsavet.setVisible(False)
else:
self.app.ui.menuprojectgeneratecnc.setVisible(False)

View File

@ -11,9 +11,11 @@ CAD program, and create G-Code for Isolation routing.
15.02.2019
- rearranged the FIle and Edit menu's and added some explanatory tooltips on certain menu items that could be seen as cryptic
- rearranged the File and Edit menu's and added some explanatory tooltips on certain menu items that could be seen as cryptic
- added Excellon Export Options in Edit -> Preferences
- started to work in using the Excellon Export parameters
- remade the Excellon export function to work with parameters entered in Edit -> Preferences -> Excellon Export
- added a new entry in the Project Context Menu named 'Save'. It will actually work for Geometry and it will do Export DXF and for Excellon and it will do Export Excellon
14.02.2019