- fixed an error in the Gerber parser; it did not took into consideration the aperture size declared before the beginning of a Gerber region. Detected for Gerber files generated by KiCAD 5.x
- in Panelize Tool made sure that for Gerber objects if one of the apertures is without geometry then it is ignored
This commit is contained in:
parent
0268a02f3b
commit
217316c732
|
@ -18,6 +18,8 @@ CAD program, and create G-Code for Isolation routing.
|
||||||
- remade the GUI in Preferences -> General grouping the settings in a more clear way
|
- remade the GUI in Preferences -> General grouping the settings in a more clear way
|
||||||
- made available the Jump To function in Excellon Editor
|
- made available the Jump To function in Excellon Editor
|
||||||
- added a clean_up() method in all the Editor Tools that need it, to be run when aborting using the ESC key
|
- added a clean_up() method in all the Editor Tools that need it, to be run when aborting using the ESC key
|
||||||
|
- fixed an error in the Gerber parser; it did not took into consideration the aperture size declared before the beginning of a Gerber region. Detected for Gerber files generated by KiCAD 5.x
|
||||||
|
- in Panelize Tool made sure that for Gerber objects if one of the apertures is without geometry then it is ignored
|
||||||
|
|
||||||
25.12.2019
|
25.12.2019
|
||||||
|
|
||||||
|
|
|
@ -437,10 +437,10 @@ class Gerber(Geometry):
|
||||||
gline = gline.strip(' \r\n')
|
gline = gline.strip(' \r\n')
|
||||||
# log.debug("Line=%3s %s" % (line_num, gline))
|
# log.debug("Line=%3s %s" % (line_num, gline))
|
||||||
|
|
||||||
# ###################
|
# ###############################################################
|
||||||
# Ignored lines #####
|
# ################ Ignored lines ############################
|
||||||
# Comments #####
|
# ################ Comments ############################
|
||||||
# ###################
|
# ###############################################################
|
||||||
match = self.comm_re.search(gline)
|
match = self.comm_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
continue
|
continue
|
||||||
|
@ -504,11 +504,11 @@ class Gerber(Geometry):
|
||||||
current_polarity = new_polarity
|
current_polarity = new_polarity
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Number format ############################################### ##
|
# ##################### Number format ###########################
|
||||||
# Example: %FSLAX24Y24*%
|
# ##################### Example: %FSLAX24Y24*% #################
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# TODO: This is ignoring most of the format. Implement the rest.
|
|
||||||
match = self.fmt_re.search(gline)
|
match = self.fmt_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
|
absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
|
||||||
|
@ -524,8 +524,10 @@ class Gerber(Geometry):
|
||||||
log.debug("Gerber format found. Coordinates type = %s (Absolute or Relative)" % absolute)
|
log.debug("Gerber format found. Coordinates type = %s (Absolute or Relative)" % absolute)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## Mode (IN/MM)
|
# ################################################################
|
||||||
# Example: %MOIN*%
|
# ######################## Mode (IN/MM) #######################
|
||||||
|
# ##################### Example: %MOIN*% #####################
|
||||||
|
# ################################################################
|
||||||
match = self.mode_re.search(gline)
|
match = self.mode_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
self.units = match.group(1)
|
self.units = match.group(1)
|
||||||
|
@ -535,9 +537,9 @@ class Gerber(Geometry):
|
||||||
self.conversion_done = True
|
self.conversion_done = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Combined Number format and Mode --- Allegro does this ####### ##
|
# Combined Number format and Mode --- Allegro does this ##########
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
match = self.fmt_re_alt.search(gline)
|
match = self.fmt_re_alt.search(gline)
|
||||||
if match:
|
if match:
|
||||||
absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
|
absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
|
||||||
|
@ -558,9 +560,9 @@ class Gerber(Geometry):
|
||||||
self.conversion_done = True
|
self.conversion_done = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Search for OrCAD way for having Number format
|
# #### Search for OrCAD way for having Number format ########
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
match = self.fmt_re_orcad.search(gline)
|
match = self.fmt_re_orcad.search(gline)
|
||||||
if match:
|
if match:
|
||||||
if match.group(1) is not None:
|
if match.group(1) is not None:
|
||||||
|
@ -587,9 +589,9 @@ class Gerber(Geometry):
|
||||||
self.conversion_done = True
|
self.conversion_done = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Units (G70/1) OBSOLETE
|
# ############ Units (G70/1) OBSOLETE ######################
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
match = self.units_re.search(gline)
|
match = self.units_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
obs_gerber_units = {'0': 'IN', '1': 'MM'}[match.group(1)]
|
obs_gerber_units = {'0': 'IN', '1': 'MM'}[match.group(1)]
|
||||||
|
@ -599,21 +601,21 @@ class Gerber(Geometry):
|
||||||
self.conversion_done = True
|
self.conversion_done = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Absolute/relative coordinates G90/1 OBSOLETE ######## ##
|
# ##### Absolute/relative coordinates G90/1 OBSOLETE ###########
|
||||||
# ##################################################### ##
|
# ################################################################
|
||||||
match = self.absrel_re.search(gline)
|
match = self.absrel_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
absolute = {'0': "Absolute", '1': "Relative"}[match.group(1)]
|
absolute = {'0': "Absolute", '1': "Relative"}[match.group(1)]
|
||||||
log.warning("Gerber obsolete coordinates type found = %s (Absolute or Relative) " % absolute)
|
log.warning("Gerber obsolete coordinates type found = %s (Absolute or Relative) " % absolute)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Aperture Macros ##################################### ##
|
# Aperture Macros ################################################
|
||||||
# Having this at the beginning will slow things down
|
# Having this at the beginning will slow things down
|
||||||
# but macros can have complicated statements than could
|
# but macros can have complicated statements than could
|
||||||
# be caught by other patterns.
|
# be caught by other patterns.
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
if current_macro is None: # No macro started yet
|
if current_macro is None: # No macro started yet
|
||||||
match = self.am1_re.search(gline)
|
match = self.am1_re.search(gline)
|
||||||
# Start macro if match, else not an AM, carry on.
|
# Start macro if match, else not an AM, carry on.
|
||||||
|
@ -640,18 +642,20 @@ class Gerber(Geometry):
|
||||||
self.aperture_macros[current_macro].append(gline)
|
self.aperture_macros[current_macro].append(gline)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## Aperture definitions %ADD...
|
# ################################################################
|
||||||
|
# ############## Aperture definitions %ADD... #################
|
||||||
|
# ################################################################
|
||||||
match = self.ad_re.search(gline)
|
match = self.ad_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
# log.info("Found aperture definition. Line %d: %s" % (line_num, gline))
|
# log.info("Found aperture definition. Line %d: %s" % (line_num, gline))
|
||||||
self.aperture_parse(match.group(1), match.group(2), match.group(3))
|
self.aperture_parse(match.group(1), match.group(2), match.group(3))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Operation code alone ###################### ##
|
# ################ Operation code alone #########################
|
||||||
# Operation code alone, usually just D03 (Flash)
|
# ########### Operation code alone, usually just D03 (Flash) ###
|
||||||
# self.opcode_re = re.compile(r'^D0?([123])\*$')
|
# self.opcode_re = re.compile(r'^D0?([123])\*$')
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
match = self.opcode_re.search(gline)
|
match = self.opcode_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
current_operation_code = int(match.group(1))
|
current_operation_code = int(match.group(1))
|
||||||
|
@ -690,10 +694,10 @@ class Gerber(Geometry):
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# Tool/aperture change
|
# ################ Tool/aperture change ########################
|
||||||
# Example: D12*
|
# ################ Example: D12* ########################
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
match = self.tool_re.search(gline)
|
match = self.tool_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
current_aperture = match.group(1)
|
current_aperture = match.group(1)
|
||||||
|
@ -740,12 +744,11 @@ class Gerber(Geometry):
|
||||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||||
|
|
||||||
path = [path[-1]]
|
path = [path[-1]]
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# G36* - Begin region
|
# ################ G36* - Begin region ########################
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
if self.regionon_re.search(gline):
|
if self.regionon_re.search(gline):
|
||||||
if len(path) > 1:
|
if len(path) > 1:
|
||||||
# Take care of what is left in the path
|
# Take care of what is left in the path
|
||||||
|
@ -780,9 +783,9 @@ class Gerber(Geometry):
|
||||||
making_region = True
|
making_region = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
# G37* - End region
|
# ################ G37* - End region ########################
|
||||||
# ############################################################# ##
|
# ################################################################
|
||||||
if self.regionoff_re.search(gline):
|
if self.regionoff_re.search(gline):
|
||||||
making_region = False
|
making_region = False
|
||||||
|
|
||||||
|
@ -830,20 +833,26 @@ class Gerber(Geometry):
|
||||||
|
|
||||||
# --- Buffered ---
|
# --- Buffered ---
|
||||||
geo_dict = dict()
|
geo_dict = dict()
|
||||||
region_f = Polygon(path).exterior
|
if current_aperture in self.apertures:
|
||||||
|
buff_value = float(self.apertures[current_aperture]['size']) / 2.0
|
||||||
|
region_geo = Polygon(path).buffer(buff_value, int(self.steps_per_circle))
|
||||||
|
else:
|
||||||
|
region_geo = Polygon(path)
|
||||||
|
|
||||||
|
region_f = region_geo.exterior
|
||||||
if not region_f.is_empty:
|
if not region_f.is_empty:
|
||||||
follow_buffer.append(region_f)
|
follow_buffer.append(region_f)
|
||||||
geo_dict['follow'] = region_f
|
geo_dict['follow'] = region_f
|
||||||
|
|
||||||
region_s = Polygon(path)
|
region_s = region_geo
|
||||||
if not region_s.is_valid:
|
if not region_s.is_valid:
|
||||||
region_s = region_s.buffer(0, int(self.steps_per_circle / 4))
|
region_s = region_s.buffer(0, int(self.steps_per_circle))
|
||||||
|
|
||||||
if not region_s.is_empty:
|
if not region_s.is_empty:
|
||||||
if self.app.defaults['gerber_simplification']:
|
if self.app.defaults['gerber_simplification']:
|
||||||
poly_buffer.append(region_s.simplify(s_tol))
|
poly_buffer.append(region_s.simplify(s_tol))
|
||||||
else:
|
else:
|
||||||
poly_buffer.append(region_s)
|
poly_buffer.append(region_s)
|
||||||
|
|
||||||
if self.is_lpc is True:
|
if self.is_lpc is True:
|
||||||
geo_dict['clear'] = region_s
|
geo_dict['clear'] = region_s
|
||||||
else:
|
else:
|
||||||
|
@ -855,18 +864,22 @@ class Gerber(Geometry):
|
||||||
path = [[current_x, current_y]] # Start new path
|
path = [[current_x, current_y]] # Start new path
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## G01/2/3* - Interpolation mode change
|
# ################################################################
|
||||||
# Can occur along with coordinates and operation code but
|
# ################ G01/2/3* - Interpolation mode change #########
|
||||||
# sometimes by itself (handled here).
|
# #### Can occur along with coordinates and operation code but ##
|
||||||
# Example: G01*
|
# #### sometimes by itself (handled here). #####################
|
||||||
|
# #### Example: G01* #####################
|
||||||
|
# ################################################################
|
||||||
match = self.interp_re.search(gline)
|
match = self.interp_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
current_interpolation_mode = int(match.group(1))
|
current_interpolation_mode = int(match.group(1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## G01 - Linear interpolation plus flashes
|
# ################################################################
|
||||||
# Operation code (D0x) missing is deprecated... oh well I will support it.
|
# ######### G01 - Linear interpolation plus flashes #############
|
||||||
|
# ######### Operation code (D0x) missing is deprecated #########
|
||||||
# REGEX: r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0([123]))?\*$'
|
# REGEX: r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0([123]))?\*$'
|
||||||
|
# ################################################################
|
||||||
match = self.lin_re.search(gline)
|
match = self.lin_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
# Dxx alone?
|
# Dxx alone?
|
||||||
|
@ -1147,7 +1160,9 @@ class Gerber(Geometry):
|
||||||
# log.debug("Line_number=%3s X=%s Y=%s (%s)" % (line_num, linear_x, linear_y, gline))
|
# log.debug("Line_number=%3s X=%s Y=%s (%s)" % (line_num, linear_x, linear_y, gline))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## G74/75* - Single or multiple quadrant arcs
|
# ################################################################
|
||||||
|
# ######### G74/75* - Single or multiple quadrant arcs ##########
|
||||||
|
# ################################################################
|
||||||
match = self.quad_re.search(gline)
|
match = self.quad_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
if match.group(1) == '4':
|
if match.group(1) == '4':
|
||||||
|
@ -1156,9 +1171,12 @@ class Gerber(Geometry):
|
||||||
quadrant_mode = 'MULTI'
|
quadrant_mode = 'MULTI'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## G02/3 - Circular interpolation
|
# ################################################################
|
||||||
# 2-clockwise, 3-counterclockwise
|
# ######### G02/3 - Circular interpolation #####################
|
||||||
# Ex. format: G03 X0 Y50 I-50 J0 where the X, Y coords are the coords of the End Point
|
# ######### 2-clockwise, 3-counterclockwise #####################
|
||||||
|
# ######### Ex. format: G03 X0 Y50 I-50 J0 where the #########
|
||||||
|
# ######### X, Y coords are the coords of the End Point #########
|
||||||
|
# ################################################################
|
||||||
match = self.circ_re.search(gline)
|
match = self.circ_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
arcdir = [None, None, "cw", "ccw"]
|
arcdir = [None, None, "cw", "ccw"]
|
||||||
|
@ -1339,12 +1357,16 @@ class Gerber(Geometry):
|
||||||
else:
|
else:
|
||||||
log.warning("Invalid arc in line %d." % line_num)
|
log.warning("Invalid arc in line %d." % line_num)
|
||||||
|
|
||||||
# ## EOF
|
# ################################################################
|
||||||
|
# ######### EOF - END OF FILE ####################################
|
||||||
|
# ################################################################
|
||||||
match = self.eof_re.search(gline)
|
match = self.eof_re.search(gline)
|
||||||
if match:
|
if match:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ## Line did not match any pattern. Warn user.
|
# ################################################################
|
||||||
|
# ######### Line did not match any pattern. Warn user. ##########
|
||||||
|
# ################################################################
|
||||||
log.warning("Line ignored (%d): %s" % (line_num, gline))
|
log.warning("Line ignored (%d): %s" % (line_num, gline))
|
||||||
|
|
||||||
if len(path) > 1:
|
if len(path) > 1:
|
||||||
|
|
|
@ -608,22 +608,22 @@ class Panelize(FlatCAMTool):
|
||||||
if panel_obj.multigeo is True:
|
if panel_obj.multigeo is True:
|
||||||
for tool in panel_obj.tools:
|
for tool in panel_obj.tools:
|
||||||
try:
|
try:
|
||||||
for pol in panel_obj.tools[tool]['solid_geometry']:
|
geo_len += len(panel_obj.tools[tool]['solid_geometry'])
|
||||||
geo_len += 1
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
geo_len = 1
|
geo_len += 1
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
for pol in panel_obj.solid_geometry:
|
geo_len = len(panel_obj.solid_geometry)
|
||||||
geo_len += 1
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
geo_len = 1
|
geo_len = 1
|
||||||
elif isinstance(panel_obj, FlatCAMGerber):
|
elif isinstance(panel_obj, FlatCAMGerber):
|
||||||
for ap in panel_obj.apertures:
|
for ap in panel_obj.apertures:
|
||||||
for elem in panel_obj.apertures[ap]['geometry']:
|
if 'geometry' in panel_obj.apertures[ap]:
|
||||||
|
try:
|
||||||
|
geo_len += len(panel_obj.apertures[ap]['geometry'])
|
||||||
|
except TypeError:
|
||||||
geo_len += 1
|
geo_len += 1
|
||||||
|
|
||||||
self.app.progress.emit(0)
|
|
||||||
element = 0
|
element = 0
|
||||||
for row in range(rows):
|
for row in range(rows):
|
||||||
currentx = 0.0
|
currentx = 0.0
|
||||||
|
@ -724,7 +724,7 @@ class Panelize(FlatCAMTool):
|
||||||
if self.app.abort_flag:
|
if self.app.abort_flag:
|
||||||
# graceful abort requested by the user
|
# graceful abort requested by the user
|
||||||
raise FlatCAMApp.GracefulException
|
raise FlatCAMApp.GracefulException
|
||||||
|
if 'geometry' in panel_obj.apertures[apid]:
|
||||||
try:
|
try:
|
||||||
# calculate the number of polygons
|
# calculate the number of polygons
|
||||||
geo_len = len(panel_obj.apertures[apid]['geometry'])
|
geo_len = len(panel_obj.apertures[apid]['geometry'])
|
||||||
|
@ -765,8 +765,7 @@ class Panelize(FlatCAMTool):
|
||||||
currenty += lenghty
|
currenty += lenghty
|
||||||
|
|
||||||
if panel_type == 'gerber':
|
if panel_type == 'gerber':
|
||||||
self.app.inform.emit('%s' %
|
self.app.inform.emit('%s' % _("Generating panel ... Adding the Gerber code."))
|
||||||
_("Generating panel ... Adding the Gerber code."))
|
|
||||||
obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
|
obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
|
||||||
local_use=obj_fin, use_thread=False)
|
local_use=obj_fin, use_thread=False)
|
||||||
|
|
||||||
|
@ -777,15 +776,11 @@ class Panelize(FlatCAMTool):
|
||||||
# app_obj.log.debug("Finished creating a cascaded union for the panel.")
|
# app_obj.log.debug("Finished creating a cascaded union for the panel.")
|
||||||
self.app.proc_container.update_view_text('')
|
self.app.proc_container.update_view_text('')
|
||||||
|
|
||||||
self.app.inform.emit('%s: %d' %
|
self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
|
||||||
(_("Generating panel... Spawning copies"), (int(rows * columns))))
|
|
||||||
if isinstance(panel_obj, FlatCAMExcellon):
|
if isinstance(panel_obj, FlatCAMExcellon):
|
||||||
self.app.progress.emit(50)
|
|
||||||
self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
|
self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
|
||||||
else:
|
else:
|
||||||
self.app.progress.emit(50)
|
self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)
|
||||||
self.app.new_object(panel_type, self.outname, job_init_geometry,
|
|
||||||
plot=True, autoselected=True)
|
|
||||||
|
|
||||||
if self.constrain_flag is False:
|
if self.constrain_flag is False:
|
||||||
self.app.inform.emit('[success] %s' % _("Panel done..."))
|
self.app.inform.emit('[success] %s' % _("Panel done..."))
|
||||||
|
|
Loading…
Reference in New Issue