- QRCode Tool: added ability to add negative QRCodes (perhaps they can be isolated on copper?); added a clear area surrounding the QRCode in case it is dropped on a copper pour (region); fixed the Gerber export
- QRCode Tool: all parameters are hard-coded for now
This commit is contained in:
parent
ee61ba63fa
commit
dfb8d21d1c
11
README.md
11
README.md
|
@ -9,12 +9,17 @@ CAD program, and create G-Code for Isolation routing.
|
||||||
|
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
|
25.10.2019
|
||||||
|
|
||||||
|
- QRCode Tool: added ability to add negative QRCodes (perhaps they can be isolated on copper?); added a clear area surrounding the QRCode in case it is dropped on a copper pour (region); fixed the Gerber export
|
||||||
|
- QRCode Tool: all parameters are hard-coded for now
|
||||||
|
|
||||||
24.10.2019
|
24.10.2019
|
||||||
|
|
||||||
- added some placeholder texts in the TextBoxes.
|
- added some placeholder texts in the TextBoxes.
|
||||||
- working on QRCode Tool; addded the utility geometry and intial functional layout
|
- working on QRCode Tool; added the utility geometry and intial functional layout
|
||||||
- working on QRCode Tool; finished adding the QRCode geometry to the selected Gerber object and also finished adding the 'follow' geometry needed when exporting the Gerber object as a Gerber file in addition to the 'solid' geometry in the obj.apertures
|
- working on QRCode Tool; finished adding the QRCode geometry to the selected Gerber object and also finished adding the 'follow' geometry needed when exporting the Gerber object as a Gerber file in addition to the 'solid' geometry in the obj.apertures
|
||||||
- working on QRCode Tool; finished offseting the goemetry both in apertures and in solid_geometry; updated the source_file of the source object
|
- working on QRCode Tool; finished offseting the geometry both in apertures and in solid_geometry; updated the source_file of the source object
|
||||||
|
|
||||||
23.10.2019
|
23.10.2019
|
||||||
|
|
||||||
|
@ -27,7 +32,7 @@ CAD program, and create G-Code for Isolation routing.
|
||||||
- working on the Calibrate Excellon Tool
|
- working on the Calibrate Excellon Tool
|
||||||
- finished the GUI layout for the Calibrate Excellon Tool
|
- finished the GUI layout for the Calibrate Excellon Tool
|
||||||
- start working on QRCode Tool - not working yet
|
- start working on QRCode Tool - not working yet
|
||||||
- start working on QRCode Tool - serching for alternatives
|
- start working on QRCode Tool - searching for alternatives
|
||||||
|
|
||||||
21.10.2019
|
21.10.2019
|
||||||
|
|
||||||
|
|
|
@ -3451,6 +3451,30 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
# Jump to coords
|
# Jump to coords
|
||||||
if key == QtCore.Qt.Key_J or key == 'J':
|
if key == QtCore.Qt.Key_J or key == 'J':
|
||||||
self.app.on_jump_to()
|
self.app.on_jump_to()
|
||||||
|
elif self.app.call_source == 'qrcode_tool':
|
||||||
|
if modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier:
|
||||||
|
if key == QtCore.Qt.Key_X:
|
||||||
|
self.app.abort_all_tasks()
|
||||||
|
return
|
||||||
|
|
||||||
|
elif modifiers == QtCore.Qt.ControlModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.ShiftModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.AltModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.NoModifier:
|
||||||
|
# Escape = Deselect All
|
||||||
|
if key == QtCore.Qt.Key_Escape or key == 'Escape':
|
||||||
|
self.app.qrcode_tool.on_exit()
|
||||||
|
|
||||||
|
# Grid toggle
|
||||||
|
if key == QtCore.Qt.Key_G:
|
||||||
|
self.app.ui.grid_snap_btn.trigger()
|
||||||
|
|
||||||
|
# Jump to coords
|
||||||
|
if key == QtCore.Qt.Key_J:
|
||||||
|
self.app.on_jump_to()
|
||||||
|
|
||||||
def createPopupMenu(self):
|
def createPopupMenu(self):
|
||||||
menu = super().createPopupMenu()
|
menu = super().createPopupMenu()
|
||||||
|
|
|
@ -11,19 +11,19 @@ from FlatCAMTool import FlatCAMTool
|
||||||
from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCDoubleSpinner
|
from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCDoubleSpinner
|
||||||
from flatcamParsers.ParseSVG import *
|
from flatcamParsers.ParseSVG import *
|
||||||
|
|
||||||
from shapely.geometry import Point
|
|
||||||
from shapely.geometry.base import *
|
from shapely.geometry.base import *
|
||||||
from shapely.ops import unary_union
|
from shapely.ops import unary_union
|
||||||
from shapely.affinity import translate
|
from shapely.affinity import translate
|
||||||
|
from shapely.geometry import box
|
||||||
|
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
import logging
|
import logging
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
import qrcode.image.svg
|
import qrcode.image.svg
|
||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
from copy import copy, deepcopy
|
|
||||||
from numpy import Inf
|
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -147,7 +147,7 @@ class QRCode(FlatCAMTool):
|
||||||
self.border_size_label = QtWidgets.QLabel('%s:' % _("Border Size"))
|
self.border_size_label = QtWidgets.QLabel('%s:' % _("Border Size"))
|
||||||
self.border_size_label.setToolTip(
|
self.border_size_label.setToolTip(
|
||||||
_("Size of the QRCode border. How many boxes thick is the border.\n"
|
_("Size of the QRCode border. How many boxes thick is the border.\n"
|
||||||
"Default value is 4.")
|
"Default value is 4. The width of the clearance around the QRCode.")
|
||||||
)
|
)
|
||||||
self.border_size_entry = FCSpinner()
|
self.border_size_entry = FCSpinner()
|
||||||
self.border_size_entry.set_range(1, 9999)
|
self.border_size_entry.set_range(1, 9999)
|
||||||
|
@ -172,15 +172,13 @@ class QRCode(FlatCAMTool):
|
||||||
# POLARITY CHOICE #
|
# POLARITY CHOICE #
|
||||||
self.pol_label = QtWidgets.QLabel('%s:' % _("Polarity"))
|
self.pol_label = QtWidgets.QLabel('%s:' % _("Polarity"))
|
||||||
self.pol_label.setToolTip(
|
self.pol_label.setToolTip(
|
||||||
_("Parameter that controls the error correction used for the QR Code.\n"
|
_("Choose the polarity of the QRCode.\n"
|
||||||
"L = maximum 7% errors can be corrected\n"
|
"It can be drawn in a negative way (squares are clear)\n"
|
||||||
"M = maximum 15% errors can be corrected\n"
|
"or in a positive way (squares are opaque).")
|
||||||
"Q = maximum 25% errors can be corrected\n"
|
|
||||||
"H = maximum 30% errors can be corrected.")
|
|
||||||
)
|
)
|
||||||
self.pol_radio = RadioSet([{'label': _('Negative'), 'value': 'neg'},
|
self.pol_radio = RadioSet([{'label': _('Negative'), 'value': 'neg'},
|
||||||
{'label': _('Positive'), 'value': 'pos'}])
|
{'label': _('Positive'), 'value': 'pos'}])
|
||||||
self.error_radio.setToolTip(
|
self.pol_radio.setToolTip(
|
||||||
_("Choose the type of QRCode to be created.\n"
|
_("Choose the type of QRCode to be created.\n"
|
||||||
"If added on a Silkscreen Gerber you may add\n"
|
"If added on a Silkscreen Gerber you may add\n"
|
||||||
"it as positive. If you add it to a Copper\n"
|
"it as positive. If you add it to a Copper\n"
|
||||||
|
@ -189,18 +187,20 @@ class QRCode(FlatCAMTool):
|
||||||
grid_lay.addWidget(self.pol_label, 7, 0)
|
grid_lay.addWidget(self.pol_label, 7, 0)
|
||||||
grid_lay.addWidget(self.pol_radio, 7, 1)
|
grid_lay.addWidget(self.pol_radio, 7, 1)
|
||||||
|
|
||||||
# BOUNDARY THICKNESS #
|
# BOUNDING BOX TYPE #
|
||||||
self.boundary_label = QtWidgets.QLabel('%s:' % _("Boundary Thickness"))
|
self.bb_label = QtWidgets.QLabel('%s:' % _("Bounding Box"))
|
||||||
self.boundary_label.setToolTip(
|
self.bb_label.setToolTip(
|
||||||
_("The width of the clearance around the QRCode.")
|
_("The bounding box, meaning the empty space that surrounds\n"
|
||||||
|
"the QRCode geometry, can have a rounded or a square shape.")
|
||||||
)
|
)
|
||||||
self.boundary_entry = FCDoubleSpinner()
|
self.bb_radio = RadioSet([{'label': _('Rounded'), 'value': 'r'},
|
||||||
self.boundary_entry.set_range(0.0, 9999.9999)
|
{'label': _('Square'), 'value': 's'}])
|
||||||
self.boundary_entry.set_precision(self.decimals)
|
self.bb_radio.setToolTip(
|
||||||
self.boundary_entry.setWrapping(True)
|
_("The bounding box, meaning the empty space that surrounds\n"
|
||||||
|
"the QRCode geometry, can have a rounded or a square shape.")
|
||||||
grid_lay.addWidget(self.boundary_label, 8, 0)
|
)
|
||||||
grid_lay.addWidget(self.boundary_entry, 8, 1)
|
grid_lay.addWidget(self.bb_label, 8, 0)
|
||||||
|
grid_lay.addWidget(self.bb_radio, 8, 1)
|
||||||
|
|
||||||
# ## Create QRCode
|
# ## Create QRCode
|
||||||
self.qrcode_button = QtWidgets.QPushButton(_("Create QRCode"))
|
self.qrcode_button = QtWidgets.QPushButton(_("Create QRCode"))
|
||||||
|
@ -213,6 +213,8 @@ class QRCode(FlatCAMTool):
|
||||||
self.layout.addStretch()
|
self.layout.addStretch()
|
||||||
|
|
||||||
self.grb_object = None
|
self.grb_object = None
|
||||||
|
self.box_poly = None
|
||||||
|
self.proc = None
|
||||||
|
|
||||||
self.origin = (0, 0)
|
self.origin = (0, 0)
|
||||||
|
|
||||||
|
@ -221,8 +223,8 @@ class QRCode(FlatCAMTool):
|
||||||
self.kr = None
|
self.kr = None
|
||||||
|
|
||||||
self.shapes = self.app.move_tool.sel_shapes
|
self.shapes = self.app.move_tool.sel_shapes
|
||||||
self.qrcode_geometry = list()
|
self.qrcode_geometry = MultiPolygon()
|
||||||
self.qrcode_utility_geometry = list()
|
self.qrcode_utility_geometry = MultiPolygon()
|
||||||
|
|
||||||
def run(self, toggle=True):
|
def run(self, toggle=True):
|
||||||
self.app.report_usage("QRCode()")
|
self.app.report_usage("QRCode()")
|
||||||
|
@ -262,73 +264,79 @@ class QRCode(FlatCAMTool):
|
||||||
self.bsize_entry.set_value(3)
|
self.bsize_entry.set_value(3)
|
||||||
self.border_size_entry.set_value(4)
|
self.border_size_entry.set_value(4)
|
||||||
self.pol_radio.set_value('pos')
|
self.pol_radio.set_value('pos')
|
||||||
|
self.bb_radio.set_value('r')
|
||||||
|
|
||||||
# Signals #
|
# Signals #
|
||||||
self.qrcode_button.clicked.connect(self.execute)
|
self.qrcode_button.clicked.connect(self.execute)
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
|
|
||||||
text_data = self.text_data.get_value()
|
text_data = self.text_data.get_value()
|
||||||
if text_data == '':
|
if text_data == '':
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Cancelled. There is no QRCode Data in the text box."))
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Cancelled. There is no QRCode Data in the text box."))
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
error_code = {
|
# get the Gerber object on which the QRCode will be inserted
|
||||||
'L': qrcode.constants.ERROR_CORRECT_L,
|
selection_index = self.grb_object_combo.currentIndex()
|
||||||
'M': qrcode.constants.ERROR_CORRECT_M,
|
model_index = self.app.collection.index(selection_index, 0, self.grb_object_combo.rootModelIndex())
|
||||||
'Q': qrcode.constants.ERROR_CORRECT_Q,
|
|
||||||
'H': qrcode.constants.ERROR_CORRECT_H
|
|
||||||
}[self.error_radio.get_value()]
|
|
||||||
|
|
||||||
qr = qrcode.QRCode(
|
try:
|
||||||
version=self.version_entry.get_value(),
|
self.grb_object = model_index.internalPointer().obj
|
||||||
error_correction=error_code,
|
except Exception as e:
|
||||||
box_size=self.bsize_entry.get_value(),
|
log.debug("QRCode.execute() --> %s" % str(e))
|
||||||
border=self.border_size_entry.get_value(),
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
||||||
image_factory=qrcode.image.svg.SvgFragmentImage
|
return 'fail'
|
||||||
)
|
|
||||||
qr.add_data(text_data)
|
|
||||||
qr.make()
|
|
||||||
|
|
||||||
svg_file = BytesIO()
|
# we can safely activate the mouse events
|
||||||
img = qr.make_image()
|
|
||||||
img.save(svg_file)
|
|
||||||
|
|
||||||
svg_text = StringIO(svg_file.getvalue().decode('UTF-8'))
|
|
||||||
svg_geometry = self.convert_svg_to_geo(svg_text, units=self.units)
|
|
||||||
self.qrcode_geometry = deepcopy(svg_geometry)
|
|
||||||
|
|
||||||
svg_geometry = unary_union(svg_geometry).buffer(0.0000001).buffer(-0.0000001)
|
|
||||||
|
|
||||||
self.qrcode_utility_geometry = svg_geometry
|
|
||||||
|
|
||||||
# if we have an object selected then we can safely activate the mouse events
|
|
||||||
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
|
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
|
||||||
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
|
self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
|
||||||
self.kr = self.app.plotcanvas.graph_event_connect('key_release', self.on_key_release)
|
self.kr = self.app.plotcanvas.graph_event_connect('key_release', self.on_key_release)
|
||||||
|
|
||||||
selection_index = self.grb_object_combo.currentIndex()
|
self.proc = self.app.proc_container.new('%s...' % _("Generating QRCode geometry"))
|
||||||
model_index = self.app.collection.index(selection_index, 0, self.grb_object_combo.rootModelIndex())
|
|
||||||
try:
|
|
||||||
self.grb_object = model_index.internalPointer().obj
|
|
||||||
except Exception as e:
|
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
|
||||||
return 'fail'
|
|
||||||
|
|
||||||
self.app.inform.emit(_("Click on the Destination point ..."))
|
def job_thread_qr(app_obj):
|
||||||
|
error_code = {
|
||||||
|
'L': qrcode.constants.ERROR_CORRECT_L,
|
||||||
|
'M': qrcode.constants.ERROR_CORRECT_M,
|
||||||
|
'Q': qrcode.constants.ERROR_CORRECT_Q,
|
||||||
|
'H': qrcode.constants.ERROR_CORRECT_H
|
||||||
|
}[self.error_radio.get_value()]
|
||||||
|
|
||||||
|
qr = qrcode.QRCode(
|
||||||
|
version=self.version_entry.get_value(),
|
||||||
|
error_correction=error_code,
|
||||||
|
box_size=self.bsize_entry.get_value(),
|
||||||
|
border=self.border_size_entry.get_value(),
|
||||||
|
image_factory=qrcode.image.svg.SvgFragmentImage
|
||||||
|
)
|
||||||
|
qr.add_data(text_data)
|
||||||
|
qr.make()
|
||||||
|
|
||||||
|
svg_file = BytesIO()
|
||||||
|
img = qr.make_image()
|
||||||
|
img.save(svg_file)
|
||||||
|
|
||||||
|
svg_text = StringIO(svg_file.getvalue().decode('UTF-8'))
|
||||||
|
svg_geometry = self.convert_svg_to_geo(svg_text, units=self.units)
|
||||||
|
self.qrcode_geometry = deepcopy(svg_geometry)
|
||||||
|
|
||||||
|
svg_geometry = unary_union(svg_geometry).buffer(0.0000001).buffer(-0.0000001)
|
||||||
|
self.qrcode_utility_geometry = svg_geometry
|
||||||
|
|
||||||
|
# make a bounding box of the QRCode geometry to help drawing the utility geometry in case it is too
|
||||||
|
# complicated
|
||||||
|
try:
|
||||||
|
a, b, c, d = self.qrcode_utility_geometry.bounds
|
||||||
|
self.box_poly = box(minx=a, miny=b, maxx=c, maxy=d)
|
||||||
|
except Exception as e:
|
||||||
|
log.debug("QRCode.make() bounds error --> %s" % str(e))
|
||||||
|
|
||||||
|
app_obj.call_source = 'qrcode_tool'
|
||||||
|
app_obj.inform.emit(_("Click on the Destination point ..."))
|
||||||
|
|
||||||
|
self.app.worker_task.emit({'fcn': job_thread_qr, 'params': [self.app]})
|
||||||
|
|
||||||
def make(self, pos):
|
def make(self, pos):
|
||||||
if self.app.is_legacy is False:
|
self.on_exit()
|
||||||
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
|
|
||||||
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
|
|
||||||
self.app.plotcanvas.graph_event_disconnect('key_release', self.on_key_release)
|
|
||||||
else:
|
|
||||||
self.app.plotcanvas.graph_event_disconnect(self.mm)
|
|
||||||
self.app.plotcanvas.graph_event_disconnect(self.mr)
|
|
||||||
self.app.plotcanvas.graph_event_disconnect(self.kr)
|
|
||||||
|
|
||||||
# delete the utility geometry
|
|
||||||
self.delete_utility_geo()
|
|
||||||
|
|
||||||
# add the svg geometry to the selected Gerber object solid_geometry and in obj.apertures, apid = 0
|
# add the svg geometry to the selected Gerber object solid_geometry and in obj.apertures, apid = 0
|
||||||
if not isinstance(self.grb_object.solid_geometry, Iterable):
|
if not isinstance(self.grb_object.solid_geometry, Iterable):
|
||||||
|
@ -339,11 +347,38 @@ class QRCode(FlatCAMTool):
|
||||||
if isinstance(self.grb_object.solid_geometry, MultiPolygon):
|
if isinstance(self.grb_object.solid_geometry, MultiPolygon):
|
||||||
geo_list = list(self.grb_object.solid_geometry.geoms)
|
geo_list = list(self.grb_object.solid_geometry.geoms)
|
||||||
|
|
||||||
|
# this is the bounding box of the QRCode geometry
|
||||||
|
a, b, c, d = self.qrcode_utility_geometry.bounds
|
||||||
|
buff_val = self.border_size_entry.get_value() * (self.bsize_entry.get_value() / 10)
|
||||||
|
|
||||||
|
if self.bb_radio.get_value() == 'r':
|
||||||
|
mask_geo = box(a, b, c, d).buffer(buff_val)
|
||||||
|
else:
|
||||||
|
mask_geo = box(a, b, c, d).buffer(buff_val, join_style=2)
|
||||||
|
|
||||||
|
# update the solid geometry with the cutout (if it is the case)
|
||||||
|
new_solid_geometry = list()
|
||||||
|
offset_mask_geo = translate(mask_geo, xoff=pos[0], yoff=pos[1])
|
||||||
|
for poly in geo_list:
|
||||||
|
if poly.contains(offset_mask_geo):
|
||||||
|
new_solid_geometry.append(poly.difference(offset_mask_geo))
|
||||||
|
else:
|
||||||
|
if poly not in new_solid_geometry:
|
||||||
|
new_solid_geometry.append(poly)
|
||||||
|
|
||||||
|
geo_list = deepcopy(list(new_solid_geometry))
|
||||||
|
|
||||||
|
# Polarity
|
||||||
|
if self.pol_radio.get_value() == 'pos':
|
||||||
|
working_geo = self.qrcode_utility_geometry
|
||||||
|
else:
|
||||||
|
working_geo = mask_geo.difference(self.qrcode_utility_geometry)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for geo in self.qrcode_utility_geometry:
|
for geo in working_geo:
|
||||||
geo_list.append(translate(geo, xoff=pos[0], yoff=pos[1]))
|
geo_list.append(translate(geo, xoff=pos[0], yoff=pos[1]))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
geo_list.append(translate(self.qrcode_utility_geometry, xoff=pos[0], yoff=pos[1]))
|
geo_list.append(translate(working_geo, xoff=pos[0], yoff=pos[1]))
|
||||||
|
|
||||||
self.grb_object.solid_geometry = deepcopy(geo_list)
|
self.grb_object.solid_geometry = deepcopy(geo_list)
|
||||||
|
|
||||||
|
@ -355,16 +390,37 @@ class QRCode(FlatCAMTool):
|
||||||
for k, v in list(self.grb_object.apertures.items()):
|
for k, v in list(self.grb_object.apertures.items()):
|
||||||
sort_apid.append(int(k))
|
sort_apid.append(int(k))
|
||||||
sorted_apertures = sorted(sort_apid)
|
sorted_apertures = sorted(sort_apid)
|
||||||
new_apid = str(max(sorted_apertures) + 1)
|
max_apid = max(sorted_apertures)
|
||||||
|
if max_apid >= 10:
|
||||||
|
new_apid = str(max_apid + 1)
|
||||||
|
else:
|
||||||
|
new_apid = '10'
|
||||||
|
|
||||||
|
# don't know if the condition is required since I already made sure above that the new_apid is a new one
|
||||||
if new_apid not in self.grb_object.apertures:
|
if new_apid not in self.grb_object.apertures:
|
||||||
self.grb_object.apertures[new_apid] = dict()
|
self.grb_object.apertures[new_apid] = dict()
|
||||||
self.grb_object.apertures[new_apid]['geometry'] = list()
|
self.grb_object.apertures[new_apid]['geometry'] = list()
|
||||||
self.grb_object.apertures[new_apid]['type'] = 'R'
|
self.grb_object.apertures[new_apid]['type'] = 'R'
|
||||||
self.grb_object.apertures[new_apid]['height'] = deepcopy(box_size)
|
# TODO: HACK
|
||||||
self.grb_object.apertures[new_apid]['width'] = deepcopy(box_size)
|
# I've artificially added 1% to the height and width because otherwise after loading the
|
||||||
|
# exported file, it will not be correctly reconstructed (it will be made from multiple shapes instead of
|
||||||
|
# one shape which show that the buffering didn't worked well). It may be the MM to INCH conversion.
|
||||||
|
self.grb_object.apertures[new_apid]['height'] = deepcopy(box_size * 1.01)
|
||||||
|
self.grb_object.apertures[new_apid]['width'] = deepcopy(box_size * 1.01)
|
||||||
self.grb_object.apertures[new_apid]['size'] = deepcopy(math.sqrt(box_size ** 2 + box_size ** 2))
|
self.grb_object.apertures[new_apid]['size'] = deepcopy(math.sqrt(box_size ** 2 + box_size ** 2))
|
||||||
|
|
||||||
|
if '0' not in self.grb_object.apertures:
|
||||||
|
self.grb_object.apertures['0'] = dict()
|
||||||
|
self.grb_object.apertures['0']['geometry'] = list()
|
||||||
|
self.grb_object.apertures['0']['type'] = 'REG'
|
||||||
|
self.grb_object.apertures['0']['size'] = 0.0
|
||||||
|
|
||||||
|
# in case that the QRCode geometry is dropped onto a copper region (found in the '0' aperture)
|
||||||
|
# make sure that I place a cutout there
|
||||||
|
zero_elem = dict()
|
||||||
|
zero_elem['clear'] = offset_mask_geo
|
||||||
|
self.grb_object.apertures['0']['geometry'].append(deepcopy(zero_elem))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
a, b, c, d = self.grb_object.bounds()
|
a, b, c, d = self.grb_object.bounds()
|
||||||
self.grb_object.options['xmin'] = a
|
self.grb_object.options['xmin'] = a
|
||||||
|
@ -383,7 +439,7 @@ class QRCode(FlatCAMTool):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
geo_elem = dict()
|
geo_elem = dict()
|
||||||
geo_elem['solid'] = self.qrcode_geometry
|
geo_elem['solid'] = self.qrcode_geometry
|
||||||
self.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
|
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
|
||||||
|
|
||||||
# update the source file with the new geometry:
|
# update the source file with the new geometry:
|
||||||
self.grb_object.source_file = self.app.export_gerber(obj_name=self.grb_object.options['name'], filename=None,
|
self.grb_object.source_file = self.app.export_gerber(obj_name=self.grb_object.options['name'], filename=None,
|
||||||
|
@ -393,29 +449,34 @@ class QRCode(FlatCAMTool):
|
||||||
|
|
||||||
def draw_utility_geo(self, pos):
|
def draw_utility_geo(self, pos):
|
||||||
|
|
||||||
face = '#0000FF' + str(hex(int(0.2 * 255)))[2:]
|
# face = '#0000FF' + str(hex(int(0.2 * 255)))[2:]
|
||||||
outline = '#0000FFAF'
|
outline = '#0000FFAF'
|
||||||
|
|
||||||
offset_geo = list()
|
offset_geo = list()
|
||||||
|
|
||||||
try:
|
# I use the len of self.qrcode_geometry instead of the utility one because the complexity of the polygons is
|
||||||
for poly in self.qrcode_utility_geometry:
|
# better seen in this
|
||||||
offset_geo.append(translate(poly.exterior, xoff=pos[0], yoff=pos[1]))
|
if len(self.qrcode_geometry) <= 330:
|
||||||
for geo_int in poly.interiors:
|
try:
|
||||||
|
for poly in self.qrcode_utility_geometry:
|
||||||
|
offset_geo.append(translate(poly.exterior, xoff=pos[0], yoff=pos[1]))
|
||||||
|
for geo_int in poly.interiors:
|
||||||
|
offset_geo.append(translate(geo_int, xoff=pos[0], yoff=pos[1]))
|
||||||
|
except TypeError:
|
||||||
|
offset_geo.append(translate(self.qrcode_utility_geometry.exterior, xoff=pos[0], yoff=pos[1]))
|
||||||
|
for geo_int in self.qrcode_utility_geometry.interiors:
|
||||||
offset_geo.append(translate(geo_int, xoff=pos[0], yoff=pos[1]))
|
offset_geo.append(translate(geo_int, xoff=pos[0], yoff=pos[1]))
|
||||||
except TypeError:
|
else:
|
||||||
offset_geo.append(translate(self.qrcode_utility_geometry.exterior, xoff=pos[0], yoff=pos[1]))
|
offset_geo = [translate(self.box_poly, xoff=pos[0], yoff=pos[1])]
|
||||||
for geo_int in self.qrcode_utility_geometry.interiors:
|
|
||||||
offset_geo.append(translate(geo_int, xoff=pos[0], yoff=pos[1]))
|
|
||||||
|
|
||||||
for shape in offset_geo:
|
for shape in offset_geo:
|
||||||
self.shapes.add(shape, color=outline, face_color=face, update=True, layer=0, tolerance=None)
|
self.shapes.add(shape, color=outline, update=True, layer=0, tolerance=None)
|
||||||
|
|
||||||
if self.app.is_legacy is True:
|
if self.app.is_legacy is True:
|
||||||
self.shapes.redraw()
|
self.shapes.redraw()
|
||||||
|
|
||||||
def delete_utility_geo(self):
|
def delete_utility_geo(self):
|
||||||
self.shapes.clear()
|
self.shapes.clear(update=True)
|
||||||
self.shapes.redraw()
|
self.shapes.redraw()
|
||||||
|
|
||||||
def on_mouse_move(self, event):
|
def on_mouse_move(self, event):
|
||||||
|
@ -514,8 +575,8 @@ class QRCode(FlatCAMTool):
|
||||||
solid_geometry += geos_text_f
|
solid_geometry += geos_text_f
|
||||||
return solid_geometry
|
return solid_geometry
|
||||||
|
|
||||||
def flatten_list(self, list):
|
def flatten_list(self, geo_list):
|
||||||
for item in list:
|
for item in geo_list:
|
||||||
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
|
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
|
||||||
yield from self.flatten_list(item)
|
yield from self.flatten_list(item)
|
||||||
else:
|
else:
|
||||||
|
@ -529,3 +590,17 @@ class QRCode(FlatCAMTool):
|
||||||
obj.plot()
|
obj.plot()
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
|
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
|
||||||
|
|
||||||
|
def on_exit(self):
|
||||||
|
if self.app.is_legacy is False:
|
||||||
|
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect('key_release', self.on_key_release)
|
||||||
|
else:
|
||||||
|
self.app.plotcanvas.graph_event_disconnect(self.mm)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect(self.mr)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect(self.kr)
|
||||||
|
|
||||||
|
# delete the utility geometry
|
||||||
|
self.delete_utility_geo()
|
||||||
|
self.app.call_source = 'app'
|
||||||
|
|
Loading…
Reference in New Issue