- 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
|
||||
- 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
|
||||
- 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
|
||||
|
||||
|
|
|
@ -437,10 +437,10 @@ class Gerber(Geometry):
|
|||
gline = gline.strip(' \r\n')
|
||||
# log.debug("Line=%3s %s" % (line_num, gline))
|
||||
|
||||
# ###################
|
||||
# Ignored lines #####
|
||||
# Comments #####
|
||||
# ###################
|
||||
# ###############################################################
|
||||
# ################ Ignored lines ############################
|
||||
# ################ Comments ############################
|
||||
# ###############################################################
|
||||
match = self.comm_re.search(gline)
|
||||
if match:
|
||||
continue
|
||||
|
@ -504,11 +504,11 @@ class Gerber(Geometry):
|
|||
current_polarity = new_polarity
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Number format ############################################### ##
|
||||
# Example: %FSLAX24Y24*%
|
||||
# ############################################################# ##
|
||||
# TODO: This is ignoring most of the format. Implement the rest.
|
||||
# ################################################################
|
||||
# ##################### Number format ###########################
|
||||
# ##################### Example: %FSLAX24Y24*% #################
|
||||
# ################################################################
|
||||
|
||||
match = self.fmt_re.search(gline)
|
||||
if match:
|
||||
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)
|
||||
continue
|
||||
|
||||
# ## Mode (IN/MM)
|
||||
# Example: %MOIN*%
|
||||
# ################################################################
|
||||
# ######################## Mode (IN/MM) #######################
|
||||
# ##################### Example: %MOIN*% #####################
|
||||
# ################################################################
|
||||
match = self.mode_re.search(gline)
|
||||
if match:
|
||||
self.units = match.group(1)
|
||||
|
@ -535,9 +537,9 @@ class Gerber(Geometry):
|
|||
self.conversion_done = True
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Combined Number format and Mode --- Allegro does this ####### ##
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# Combined Number format and Mode --- Allegro does this ##########
|
||||
# ################################################################
|
||||
match = self.fmt_re_alt.search(gline)
|
||||
if match:
|
||||
absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
|
||||
|
@ -558,9 +560,9 @@ class Gerber(Geometry):
|
|||
self.conversion_done = True
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Search for OrCAD way for having Number format
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# #### Search for OrCAD way for having Number format ########
|
||||
# ################################################################
|
||||
match = self.fmt_re_orcad.search(gline)
|
||||
if match:
|
||||
if match.group(1) is not None:
|
||||
|
@ -587,9 +589,9 @@ class Gerber(Geometry):
|
|||
self.conversion_done = True
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Units (G70/1) OBSOLETE
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# ############ Units (G70/1) OBSOLETE ######################
|
||||
# ################################################################
|
||||
match = self.units_re.search(gline)
|
||||
if match:
|
||||
obs_gerber_units = {'0': 'IN', '1': 'MM'}[match.group(1)]
|
||||
|
@ -599,21 +601,21 @@ class Gerber(Geometry):
|
|||
self.conversion_done = True
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Absolute/relative coordinates G90/1 OBSOLETE ######## ##
|
||||
# ##################################################### ##
|
||||
# ################################################################
|
||||
# ##### Absolute/relative coordinates G90/1 OBSOLETE ###########
|
||||
# ################################################################
|
||||
match = self.absrel_re.search(gline)
|
||||
if match:
|
||||
absolute = {'0': "Absolute", '1': "Relative"}[match.group(1)]
|
||||
log.warning("Gerber obsolete coordinates type found = %s (Absolute or Relative) " % absolute)
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Aperture Macros ##################################### ##
|
||||
# ################################################################
|
||||
# Aperture Macros ################################################
|
||||
# Having this at the beginning will slow things down
|
||||
# but macros can have complicated statements than could
|
||||
# be caught by other patterns.
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
if current_macro is None: # No macro started yet
|
||||
match = self.am1_re.search(gline)
|
||||
# Start macro if match, else not an AM, carry on.
|
||||
|
@ -640,18 +642,20 @@ class Gerber(Geometry):
|
|||
self.aperture_macros[current_macro].append(gline)
|
||||
continue
|
||||
|
||||
# ## Aperture definitions %ADD...
|
||||
# ################################################################
|
||||
# ############## Aperture definitions %ADD... #################
|
||||
# ################################################################
|
||||
match = self.ad_re.search(gline)
|
||||
if match:
|
||||
# log.info("Found aperture definition. Line %d: %s" % (line_num, gline))
|
||||
self.aperture_parse(match.group(1), match.group(2), match.group(3))
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Operation code alone ###################### ##
|
||||
# Operation code alone, usually just D03 (Flash)
|
||||
# ################################################################
|
||||
# ################ Operation code alone #########################
|
||||
# ########### Operation code alone, usually just D03 (Flash) ###
|
||||
# self.opcode_re = re.compile(r'^D0?([123])\*$')
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
match = self.opcode_re.search(gline)
|
||||
if match:
|
||||
current_operation_code = int(match.group(1))
|
||||
|
@ -690,10 +694,10 @@ class Gerber(Geometry):
|
|||
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# Tool/aperture change
|
||||
# Example: D12*
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# ################ Tool/aperture change ########################
|
||||
# ################ Example: D12* ########################
|
||||
# ################################################################
|
||||
match = self.tool_re.search(gline)
|
||||
if match:
|
||||
current_aperture = match.group(1)
|
||||
|
@ -740,12 +744,11 @@ class Gerber(Geometry):
|
|||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
||||
path = [path[-1]]
|
||||
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# G36* - Begin region
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# ################ G36* - Begin region ########################
|
||||
# ################################################################
|
||||
if self.regionon_re.search(gline):
|
||||
if len(path) > 1:
|
||||
# Take care of what is left in the path
|
||||
|
@ -780,9 +783,9 @@ class Gerber(Geometry):
|
|||
making_region = True
|
||||
continue
|
||||
|
||||
# ############################################################# ##
|
||||
# G37* - End region
|
||||
# ############################################################# ##
|
||||
# ################################################################
|
||||
# ################ G37* - End region ########################
|
||||
# ################################################################
|
||||
if self.regionoff_re.search(gline):
|
||||
making_region = False
|
||||
|
||||
|
@ -830,20 +833,26 @@ class Gerber(Geometry):
|
|||
|
||||
# --- Buffered ---
|
||||
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:
|
||||
follow_buffer.append(region_f)
|
||||
geo_dict['follow'] = region_f
|
||||
|
||||
region_s = Polygon(path)
|
||||
region_s = region_geo
|
||||
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 self.app.defaults['gerber_simplification']:
|
||||
poly_buffer.append(region_s.simplify(s_tol))
|
||||
else:
|
||||
poly_buffer.append(region_s)
|
||||
|
||||
if self.is_lpc is True:
|
||||
geo_dict['clear'] = region_s
|
||||
else:
|
||||
|
@ -855,18 +864,22 @@ class Gerber(Geometry):
|
|||
path = [[current_x, current_y]] # Start new path
|
||||
continue
|
||||
|
||||
# ## G01/2/3* - Interpolation mode change
|
||||
# Can occur along with coordinates and operation code but
|
||||
# sometimes by itself (handled here).
|
||||
# Example: G01*
|
||||
# ################################################################
|
||||
# ################ G01/2/3* - Interpolation mode change #########
|
||||
# #### Can occur along with coordinates and operation code but ##
|
||||
# #### sometimes by itself (handled here). #####################
|
||||
# #### Example: G01* #####################
|
||||
# ################################################################
|
||||
match = self.interp_re.search(gline)
|
||||
if match:
|
||||
current_interpolation_mode = int(match.group(1))
|
||||
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]))?\*$'
|
||||
# ################################################################
|
||||
match = self.lin_re.search(gline)
|
||||
if match:
|
||||
# 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))
|
||||
continue
|
||||
|
||||
# ## G74/75* - Single or multiple quadrant arcs
|
||||
# ################################################################
|
||||
# ######### G74/75* - Single or multiple quadrant arcs ##########
|
||||
# ################################################################
|
||||
match = self.quad_re.search(gline)
|
||||
if match:
|
||||
if match.group(1) == '4':
|
||||
|
@ -1156,9 +1171,12 @@ class Gerber(Geometry):
|
|||
quadrant_mode = 'MULTI'
|
||||
continue
|
||||
|
||||
# ## G02/3 - Circular interpolation
|
||||
# 2-clockwise, 3-counterclockwise
|
||||
# Ex. format: G03 X0 Y50 I-50 J0 where the X, Y coords are the coords of the End Point
|
||||
# ################################################################
|
||||
# ######### G02/3 - Circular interpolation #####################
|
||||
# ######### 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)
|
||||
if match:
|
||||
arcdir = [None, None, "cw", "ccw"]
|
||||
|
@ -1339,12 +1357,16 @@ class Gerber(Geometry):
|
|||
else:
|
||||
log.warning("Invalid arc in line %d." % line_num)
|
||||
|
||||
# ## EOF
|
||||
# ################################################################
|
||||
# ######### EOF - END OF FILE ####################################
|
||||
# ################################################################
|
||||
match = self.eof_re.search(gline)
|
||||
if match:
|
||||
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))
|
||||
|
||||
if len(path) > 1:
|
||||
|
|
|
@ -608,22 +608,22 @@ class Panelize(FlatCAMTool):
|
|||
if panel_obj.multigeo is True:
|
||||
for tool in panel_obj.tools:
|
||||
try:
|
||||
for pol in panel_obj.tools[tool]['solid_geometry']:
|
||||
geo_len += 1
|
||||
geo_len += len(panel_obj.tools[tool]['solid_geometry'])
|
||||
except TypeError:
|
||||
geo_len = 1
|
||||
geo_len += 1
|
||||
else:
|
||||
try:
|
||||
for pol in panel_obj.solid_geometry:
|
||||
geo_len += 1
|
||||
geo_len = len(panel_obj.solid_geometry)
|
||||
except TypeError:
|
||||
geo_len = 1
|
||||
elif isinstance(panel_obj, FlatCAMGerber):
|
||||
for ap in panel_obj.apertures:
|
||||
for elem in panel_obj.apertures[ap]['geometry']:
|
||||
geo_len += 1
|
||||
if 'geometry' in panel_obj.apertures[ap]:
|
||||
try:
|
||||
geo_len += len(panel_obj.apertures[ap]['geometry'])
|
||||
except TypeError:
|
||||
geo_len += 1
|
||||
|
||||
self.app.progress.emit(0)
|
||||
element = 0
|
||||
for row in range(rows):
|
||||
currentx = 0.0
|
||||
|
@ -724,49 +724,48 @@ class Panelize(FlatCAMTool):
|
|||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
if 'geometry' in panel_obj.apertures[apid]:
|
||||
try:
|
||||
# calculate the number of polygons
|
||||
geo_len = len(panel_obj.apertures[apid]['geometry'])
|
||||
except TypeError:
|
||||
geo_len = 1
|
||||
pol_nr = 0
|
||||
for el in panel_obj.apertures[apid]['geometry']:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
try:
|
||||
# calculate the number of polygons
|
||||
geo_len = len(panel_obj.apertures[apid]['geometry'])
|
||||
except TypeError:
|
||||
geo_len = 1
|
||||
pol_nr = 0
|
||||
for el in panel_obj.apertures[apid]['geometry']:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
new_el = dict()
|
||||
if 'solid' in el:
|
||||
geo_aper = translate_recursion(el['solid'])
|
||||
new_el['solid'] = geo_aper
|
||||
|
||||
new_el = dict()
|
||||
if 'solid' in el:
|
||||
geo_aper = translate_recursion(el['solid'])
|
||||
new_el['solid'] = geo_aper
|
||||
if 'clear' in el:
|
||||
geo_aper = translate_recursion(el['clear'])
|
||||
new_el['clear'] = geo_aper
|
||||
|
||||
if 'clear' in el:
|
||||
geo_aper = translate_recursion(el['clear'])
|
||||
new_el['clear'] = geo_aper
|
||||
if 'follow' in el:
|
||||
geo_aper = translate_recursion(el['follow'])
|
||||
new_el['follow'] = geo_aper
|
||||
|
||||
if 'follow' in el:
|
||||
geo_aper = translate_recursion(el['follow'])
|
||||
new_el['follow'] = geo_aper
|
||||
obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
|
||||
|
||||
obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
|
||||
pol_nr += 1
|
||||
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
pol_nr += 1
|
||||
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
||||
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
||||
(_("Copy"),
|
||||
int(element),
|
||||
disp_number))
|
||||
old_disp_number = disp_number
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %s: %d %d%%' %
|
||||
(_("Copy"),
|
||||
int(element),
|
||||
disp_number))
|
||||
old_disp_number = disp_number
|
||||
|
||||
currentx += lenghtx
|
||||
currenty += lenghty
|
||||
|
||||
if panel_type == 'gerber':
|
||||
self.app.inform.emit('%s' %
|
||||
_("Generating panel ... Adding the Gerber code."))
|
||||
self.app.inform.emit('%s' % _("Generating panel ... Adding the Gerber code."))
|
||||
obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
|
||||
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.")
|
||||
self.app.proc_container.update_view_text('')
|
||||
|
||||
self.app.inform.emit('%s: %d' %
|
||||
(_("Generating panel... Spawning copies"), (int(rows * columns))))
|
||||
self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
|
||||
if isinstance(panel_obj, FlatCAMExcellon):
|
||||
self.app.progress.emit(50)
|
||||
self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
|
||||
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:
|
||||
self.app.inform.emit('[success] %s' % _("Panel done..."))
|
||||
|
|
Loading…
Reference in New Issue