- rework the Gerber parser

This commit is contained in:
Marius Stanciu 2019-05-09 03:43:17 +03:00
parent 28fce82432
commit 3d113c89b1
2 changed files with 268 additions and 441 deletions

View File

@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
================================================= =================================================
9.05.2019
- rework the Gerber parser
8.05.2019 8.05.2019
- added zoom fit for Set Origin command - added zoom fit for Set Origin command

705
camlib.py
View File

@ -1920,14 +1920,19 @@ class Gerber (Geometry):
''' '''
apertures = { apertures = {
'id':{ 'id':{
'type':chr, 'type':string,
'size':float, 'size':float,
'width':float, 'width':float,
'height':float, 'height':float,
'solid_geometry': [], 'geometry': [],
'follow_geometry': [],
} }
} }
apertures['geometry'] list elements are dicts
dict = {
'solid': [],
'follow': [],
'clear': []
}
''' '''
# aperture storage # aperture storage
@ -2227,7 +2232,7 @@ class Gerber (Geometry):
### Cleanup ### Cleanup
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
@ -2244,37 +2249,30 @@ class Gerber (Geometry):
new_polarity = match.group(1) new_polarity = match.group(1)
# log.info("Polarity CHANGE, LPC = %s, poly_buff = %s" % (self.is_lpc, poly_buffer)) # log.info("Polarity CHANGE, LPC = %s, poly_buff = %s" % (self.is_lpc, poly_buffer))
self.is_lpc = True if new_polarity == 'C' else False self.is_lpc = True if new_polarity == 'C' else False
if len(path) > 1 and current_polarity != new_polarity: if len(path) > 1 and current_polarity != new_polarity:
# finish the current path and add it to the storage # finish the current path and add it to the storage
# --- Buffered ---- # --- Buffered ----
width = self.apertures[last_path_aperture]["size"] width = self.apertures[last_path_aperture]["size"]
geo = LineString(path) if path:
if not geo.is_empty: geo_f = LineString(path)
follow_buffer.append(geo) geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
try: follow_buffer.append(geo_f)
self.apertures[last_path_aperture]['follow_geometry'].append(geo) poly_buffer.append(geo_s)
except KeyError:
self.apertures[last_path_aperture]['follow_geometry'] = []
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4)) geo_dict = dict()
geo_dict['follow'] = geo_f
if not geo.is_empty: if self.is_lpc:
poly_buffer.append(geo) geo_dict['clear'] = geo_s
if self.is_lpc is True:
try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[last_path_aperture]['solid_geometry'].append(geo) try:
except KeyError: self.apertures[last_path_aperture]['geometry'].append(geo_dict)
self.apertures[last_path_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[last_path_aperture]['solid_geometry'].append(geo) self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
path = [path[-1]] path = [path[-1]]
@ -2437,28 +2435,26 @@ class Gerber (Geometry):
flash = Gerber.create_flash_geometry( flash = Gerber.create_flash_geometry(
Point(current_x, current_y), self.apertures[current_aperture], Point(current_x, current_y), self.apertures[current_aperture],
int(self.steps_per_circle)) int(self.steps_per_circle))
if not flash.is_empty:
poly_buffer.append(flash)
if self.is_lpc is True:
try:
self.apertures[current_aperture]['clear_geometry'].append(flash)
except KeyError:
self.apertures[current_aperture]['clear_geometry'] = []
self.apertures[current_aperture]['clear_geometry'].append(flash)
else:
try:
self.apertures[current_aperture]['follow_geometry'].append(Point(
current_x, current_y))
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(Point(
current_x, current_y))
try: if not flash.is_empty:
self.apertures[current_aperture]['solid_geometry'].append(flash) geo_f = Point(current_x, current_y)
except KeyError: geo_s = flash
self.apertures[current_aperture]['solid_geometry'] = [] # follow_buffer.append(geo_f)
self.apertures[current_aperture]['solid_geometry'].append(flash) poly_buffer.append(geo_s)
geo_dict = dict()
geo_dict['follow'] = geo_f
if self.is_lpc:
geo_dict['clear'] = geo_s
else:
geo_dict['solid'] = geo_s
try:
self.apertures[current_aperture]['geometry'].append(geo_dict)
except KeyError:
self.apertures[current_aperture] = dict()
self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(geo_dict)
except IndexError: except IndexError:
log.warning("Line %d: %s -> Nothing there to flash!" % (line_num, gline)) log.warning("Line %d: %s -> Nothing there to flash!" % (line_num, gline))
@ -2482,37 +2478,25 @@ class Gerber (Geometry):
# Take care of the current path with the previous tool # Take care of the current path with the previous tool
if len(path) > 1: if len(path) > 1:
if self.apertures[last_path_aperture]["type"] == 'R': if self.apertures[current_aperture]["type"] != 'R':
# do nothing because 'R' type moving aperture is none at once width = self.apertures[current_aperture]["size"]
pass
else:
geo = LineString(path) geo_f = LineString(path)
if not geo.is_empty: geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
follow_buffer.append(geo) follow_buffer.append(geo_f)
try: poly_buffer.append(geo_s)
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['follow_geometry'] = []
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
# --- Buffered ---- geo_dict = dict()
width = self.apertures[last_path_aperture]["size"] geo_dict['follow'] = geo_f
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4)) if self.is_lpc:
if not geo.is_empty: geo_dict['clear'] = geo_s
poly_buffer.append(geo) else:
if self.is_lpc is True: geo_dict['solid'] = geo_s
try: try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo) self.apertures[current_aperture]['geometry'].append(geo_dict)
except KeyError: except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = [] self.apertures[current_aperture]['geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo) self.apertures[current_aperture]['geometry'].append(geo_dict)
else:
try:
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
path = [path[-1]] path = [path[-1]]
@ -2523,33 +2507,24 @@ class Gerber (Geometry):
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
## --- Buffered ---
width = self.apertures[last_path_aperture]["size"] width = self.apertures[last_path_aperture]["size"]
geo = LineString(path) geo_f = LineString(path)
if not geo.is_empty: geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
follow_buffer.append(geo) follow_buffer.append(geo_f)
try: poly_buffer.append(geo_s)
self.apertures[current_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(geo)
geo = LineString(path).buffer(width/1.999, int(self.steps_per_circle / 4)) geo_dict = dict()
if not geo.is_empty: geo_dict['follow'] = geo_f
poly_buffer.append(geo) if self.is_lpc:
if self.is_lpc is True: geo_dict['clear'] = geo_s
try: else:
self.apertures[last_path_aperture]['clear_geometry'].append(geo) geo_dict['solid'] = geo_s
except KeyError: try:
self.apertures[last_path_aperture]['clear_geometry'] = [] self.apertures[last_path_aperture]['geometry'].append(geo_dict)
self.apertures[last_path_aperture]['clear_geometry'].append(geo) except KeyError:
else: self.apertures[last_path_aperture]['geometry'] = []
try: self.apertures[last_path_aperture]['geometry'].append(geo_dict)
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
path = [path[-1]] path = [path[-1]]
@ -2564,94 +2539,62 @@ class Gerber (Geometry):
self.apertures['0'] = {} self.apertures['0'] = {}
self.apertures['0']['type'] = 'REG' self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0 self.apertures['0']['size'] = 0.0
self.apertures['0']['solid_geometry'] = [] self.apertures['0']['geometry'] = []
# if D02 happened before G37 we now have a path with 1 element only so we have to add the current # if D02 happened before G37 we now have a path with 1 element only so we have to add the current
# geo to the poly_buffer otherwise we loose it # geo to the poly_buffer otherwise we loose it
if current_operation_code == 2: # if current_operation_code == 2:
if geo: # if geo:
if not geo.is_empty: # if not geo.is_empty:
follow_buffer.append(geo) # follow_buffer.append(geo)
try: # try:
self.apertures['0']['follow_geometry'].append(geo) # self.apertures['0']['follow_geometry'].append(geo)
except KeyError: # except KeyError:
self.apertures['0']['follow_geometry'] = [] # self.apertures['0']['follow_geometry'] = []
self.apertures['0']['follow_geometry'].append(geo) # self.apertures['0']['follow_geometry'].append(geo)
#
poly_buffer.append(geo) # poly_buffer.append(geo)
if self.is_lpc is True: # if self.is_lpc is True:
try: # try:
self.apertures['0']['clear_geometry'].append(geo) # self.apertures['0']['clear_geometry'].append(geo)
except KeyError: # except KeyError:
self.apertures['0']['clear_geometry'] = [] # self.apertures['0']['clear_geometry'] = []
self.apertures['0']['clear_geometry'].append(geo) # self.apertures['0']['clear_geometry'].append(geo)
else: # else:
try: # try:
self.apertures['0']['solid_geometry'].append(geo) # self.apertures['0']['solid_geometry'].append(geo)
except KeyError: # except KeyError:
self.apertures['0']['solid_geometry'] = [] # self.apertures['0']['solid_geometry'] = []
self.apertures['0']['solid_geometry'].append(geo) # self.apertures['0']['solid_geometry'].append(geo)
continue # continue
# Only one path defines region? # Only one path defines region?
# This can happen if D02 happened before G37 and # This can happen if D02 happened before G37 and
# is not and error. # is not and error.
if len(path) < 3: if len(path) < 3:
# print "ERROR: Path contains less than 3 points:"
# print path
# print "Line (%d): " % line_num, gline
# path = []
#path = [[current_x, current_y]]
continue continue
# For regions we may ignore an aperture that is None geo_f = LineString(path)
# self.regions.append({"polygon": Polygon(path), geo_s = Polygon(path)
# "aperture": last_path_aperture}) if not geo_s.is_valid:
geo_s = geo_s.buffer(0, int(self.steps_per_circle / 4))
follow_buffer.append(geo_f)
if not geo_s.is_empty:
poly_buffer.append(geo_s)
# --- Buffered --- geo_dict = dict()
geo_dict['follow'] = geo_f
region = Polygon() if not geo_s.is_empty:
if not region.is_empty: if self.is_lpc:
follow_buffer.append(region) geo_dict['clear'] = geo_s
try:
self.apertures['0']['follow_geometry'].append(region)
except KeyError:
self.apertures['0']['follow_geometry'] = []
self.apertures['0']['follow_geometry'].append(region)
region = Polygon(path)
if not region.is_valid:
region = region.buffer(0, int(self.steps_per_circle / 4))
if not region.is_empty:
poly_buffer.append(region)
# we do this for the case that a region is done without having defined any aperture
# Allegro does that
# if current_aperture:
# used_aperture = current_aperture
# elif last_path_aperture:
# used_aperture = last_path_aperture
# else:
# if '0' not in self.apertures:
# self.apertures['0'] = {}
# self.apertures['0']['size'] = 0.0
# self.apertures['0']['type'] = 'REG'
# self.apertures['0']['solid_geometry'] = []
# used_aperture = '0'
used_aperture = '0'
if self.is_lpc is True:
try:
self.apertures[used_aperture]['clear_geometry'].append(region)
except KeyError:
self.apertures[used_aperture]['clear_geometry'] = []
self.apertures[used_aperture]['clear_geometry'].append(region)
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[used_aperture]['solid_geometry'].append(region) try:
except KeyError: self.apertures['0']['geometry'].append(geo_dict)
self.apertures[used_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[used_aperture]['solid_geometry'].append(region) self.apertures['0'] = dict()
self.apertures['0']['geometry'] = []
self.apertures['0']['geometry'].append(geo_dict)
path = [[current_x, current_y]] # Start new path path = [[current_x, current_y]] # Start new path
continue continue
@ -2717,33 +2660,36 @@ class Gerber (Geometry):
maxx = max(path[0][0], path[1][0]) + width / 2 maxx = max(path[0][0], path[1][0]) + width / 2
miny = min(path[0][1], path[1][1]) - height / 2 miny = min(path[0][1], path[1][1]) - height / 2
maxy = max(path[0][1], path[1][1]) + height / 2 maxy = max(path[0][1], path[1][1]) + height / 2
log.debug("Coords: %s - %s - %s - %s" % (minx, miny, maxx, maxy)) # log.debug("Coords: %s - %s - %s - %s" % (minx, miny, maxx, maxy))
geo = shply_box(minx, miny, maxx, maxy) r_x = maxx - minx
poly_buffer.append(geo) r_y = maxy - miny
if self.is_lpc is True: geo_f = Point(r_x, r_y)
try: geo_s = shply_box(minx, miny, maxx, maxy)
self.apertures[current_aperture]['clear_geometry'].append(geo) follow_buffer.append(geo_f)
except KeyError: poly_buffer.append(geo_s)
self.apertures[current_aperture]['clear_geometry'] = []
self.apertures[current_aperture]['clear_geometry'].append(geo) geo_dict = dict()
geo_dict['follow'] = geo_f
if self.is_lpc:
geo_dict['clear'] = geo_s
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[current_aperture]['solid_geometry'].append(geo) try:
except KeyError: self.apertures[current_aperture]['geometry'].append(geo_dict)
self.apertures[current_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[current_aperture]['solid_geometry'].append(geo) self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(geo_dict)
except: except:
pass pass
last_path_aperture = current_aperture last_path_aperture = current_aperture
# we do this for the case that a region is done without having defined any aperture
# Allegro does that
if last_path_aperture is None: if last_path_aperture is None:
if '0' not in self.apertures: if '0' not in self.apertures:
self.apertures['0'] = {} self.apertures['0'] = {}
self.apertures['0']['type'] = 'REG' self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0 self.apertures['0']['size'] = 0.0
self.apertures['0']['solid_geometry'] = [] self.apertures['0']['geometry'] = []
last_path_aperture = '0' last_path_aperture = '0'
else: else:
self.app.inform.emit(_("[WARNING] Coordinates missing, line ignored: %s") % str(gline)) self.app.inform.emit(_("[WARNING] Coordinates missing, line ignored: %s") % str(gline))
@ -2753,100 +2699,47 @@ class Gerber (Geometry):
if len(path) > 1: if len(path) > 1:
geo = None geo = None
# --- BUFFERED --- if last_path_aperture is None:
# this treats the case when we are storing geometry as paths only if '0' not in self.apertures:
if making_region: self.apertures['0'] = {}
# we do this for the case that a region is done without having defined any aperture self.apertures['0']['type'] = 'REG'
# Allegro does that self.apertures['0']['size'] = 0.0
if last_path_aperture is None: self.apertures['0']['geometry'] = []
if '0' not in self.apertures: last_path_aperture = '0'
self.apertures['0'] = {} width = 0
self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0
self.apertures['0']['solid_geometry'] = []
last_path_aperture = '0'
geo = Polygon()
else: else:
geo = LineString(path) width = self.apertures[last_path_aperture]["size"]
try: if path and self.apertures[last_path_aperture]["type"] != 'R':
if self.apertures[last_path_aperture]["type"] != 'R': geo_f = LineString(path)
if not geo.is_empty: geo_s = None
follow_buffer.append(geo)
try: if making_region:
self.apertures[current_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(geo)
except Exception as e:
log.debug("camlib.Gerber.parse_lines() --> %s" % str(e))
if not geo.is_empty:
follow_buffer.append(geo)
try: try:
self.apertures[current_aperture]['follow_geometry'].append(geo) geo_s = Polygon(path)
except KeyError: poly_buffer.append(geo_s)
self.apertures[current_aperture]['follow_geometry'] = [] except ValueError:
self.apertures[current_aperture]['follow_geometry'].append(geo) log.warning("Problem %s %s" % (gline, line_num))
self.app.inform.emit(_("[ERROR] Region does not have enough points. "
# this treats the case when we are storing geometry as solids "File will be processed but there are parser errors. "
if making_region: "Line number: %s") % str(line_num))
# we do this for the case that a region is done without having defined any aperture
# Allegro does that
if last_path_aperture is None:
if '0' not in self.apertures:
self.apertures['0'] = {}
self.apertures['0']['type'] = 'REG'
self.apertures['0']['size'] = 0.0
self.apertures['0']['solid_geometry'] = []
last_path_aperture = '0'
# elem = [current_x, current_y]
# if elem != path[-1]:
# path.append([current_x, current_y])
try:
geo = Polygon(path)
except ValueError:
log.warning("Problem %s %s" % (gline, line_num))
self.app.inform.emit(_("[ERROR] Region does not have enough points. "
"File will be processed but there are parser errors. "
"Line number: %s") % str(line_num))
else:
if last_path_aperture is None:
log.warning("No aperture defined for curent path. (%d)" % line_num)
width = self.apertures[last_path_aperture]["size"] # TODO: WARNING this should fail!
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
try:
if self.apertures[last_path_aperture]["type"] != 'R':
if not geo.is_empty:
poly_buffer.append(geo)
if self.is_lpc is True:
try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
else:
try:
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except Exception as e:
log.debug("camlib.Gerber.parse_lines() --> %s" % str(e))
poly_buffer.append(geo)
if self.is_lpc is True:
try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
else: else:
try: geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
self.apertures[last_path_aperture]['solid_geometry'].append(geo) poly_buffer.append(geo_s)
except KeyError: follow_buffer.append(geo_f)
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo) geo_dict = dict()
geo_dict['follow'] = geo_f
if geo_s:
if self.is_lpc:
geo_dict['clear'] = geo_s
else:
geo_dict['solid'] = geo_s
try:
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
except KeyError:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
# if linear_x or linear_y are None, ignore those # if linear_x or linear_y are None, ignore those
if linear_x is not None and linear_y is not None: if linear_x is not None and linear_y is not None:
@ -2859,98 +2752,53 @@ class Gerber (Geometry):
# Not allowed in region mode. # Not allowed in region mode.
elif current_operation_code == 3: elif current_operation_code == 3:
# Create path draw so far. # finished the path draw until now
if len(path) > 1: width = self.apertures[last_path_aperture]["size"]
# --- Buffered ----
# this treats the case when we are storing geometry as paths if len(path) > 1 and self.apertures[last_path_aperture]["type"] != 'R':
geo = LineString(path) geo_f = LineString(path)
if not geo.is_empty: geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
try: follow_buffer.append(geo_f)
if self.apertures[last_path_aperture]["type"] != 'R': poly_buffer.append(geo_s)
follow_buffer.append(geo)
try:
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['follow_geometry'] = []
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
except Exception as e:
log.debug("camlib.Gerber.parse_lines() --> G01 match D03 --> %s" % str(e))
follow_buffer.append(geo)
try:
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['follow_geometry'] = []
self.apertures[last_path_aperture]['follow_geometry'].append(geo)
# this treats the case when we are storing geometry as solids
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
try:
if self.apertures[last_path_aperture]["type"] != 'R':
poly_buffer.append(geo)
if self.is_lpc is True:
try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
else:
try:
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except:
poly_buffer.append(geo)
if self.is_lpc is True:
try:
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(geo)
else:
try:
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
except KeyError:
self.apertures[last_path_aperture]['solid_geometry'] = []
self.apertures[last_path_aperture]['solid_geometry'].append(geo)
geo_dict = dict()
geo_dict['follow'] = geo_f
if self.is_lpc:
geo_dict['clear'] = geo_s
else:
geo_dict['solid'] = geo_s
try:
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
except KeyError:
self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
# Reset path starting point # Reset path starting point
path = [[linear_x, linear_y]] path = [[linear_x, linear_y]]
# --- BUFFERED ---
# Draw the flash
# this treats the case when we are storing geometry as paths
geo_flash = Point([linear_x, linear_y])
follow_buffer.append(geo_flash)
try:
self.apertures[current_aperture]['follow_geometry'].append(geo_flash)
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(geo_flash)
# this treats the case when we are storing geometry as solids # Draw the flash
flash = Gerber.create_flash_geometry( geo_f = Point(linear_x, linear_y)
Point( [linear_x, linear_y]), geo_s = Gerber.create_flash_geometry(
Point([linear_x, linear_y]),
self.apertures[current_aperture], self.apertures[current_aperture],
int(self.steps_per_circle) int(self.steps_per_circle)
) )
if not flash.is_empty: follow_buffer.append(geo_f)
poly_buffer.append(flash) if not geo_s.is_empty:
if self.is_lpc is True: poly_buffer.append(geo_s)
try:
self.apertures[current_aperture]['clear_geometry'].append(flash) geo_dict = dict()
except KeyError: geo_dict['follow'] = geo_f
self.apertures[current_aperture]['clear_geometry'] = [] if not geo_s.is_empty:
self.apertures[current_aperture]['clear_geometry'].append(flash) if self.is_lpc:
geo_dict['clear'] = geo_s
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[current_aperture]['solid_geometry'].append(flash) try:
except KeyError: self.apertures[current_aperture]['geometry'].append(geo_dict)
self.apertures[current_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[current_aperture]['solid_geometry'].append(flash) self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(geo_dict)
# maybe those lines are not exactly needed but it is easier to read the program as those coordinates # maybe those lines are not exactly needed but it is easier to read the program as those coordinates
# are used in case that circular interpolation is encountered within the Gerber file # are used in case that circular interpolation is encountered within the Gerber file
@ -3024,6 +2872,8 @@ class Gerber (Geometry):
# Nothing created! Pen Up. # Nothing created! Pen Up.
if current_operation_code == 2: if current_operation_code == 2:
log.warning("Arc with D2. (%d)" % line_num) log.warning("Arc with D2. (%d)" % line_num)
# if we have something drawn until this moment, add it
if len(path) > 1: if len(path) > 1:
if last_path_aperture is None: if last_path_aperture is None:
log.warning("No aperture defined for curent path. (%d)" % line_num) log.warning("No aperture defined for curent path. (%d)" % line_num)
@ -3031,32 +2881,24 @@ class Gerber (Geometry):
# --- BUFFERED --- # --- BUFFERED ---
width = self.apertures[last_path_aperture]["size"] width = self.apertures[last_path_aperture]["size"]
# this treats the case when we are storing geometry as paths geo_f = LineString(path)
geo = LineString(path) geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty: if not geo_s.is_empty:
follow_buffer.append(geo) follow_buffer.append(geo_f)
try: poly_buffer.append(geo_s)
self.apertures[current_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(geo)
# this treats the case when we are storing geometry as solids geo_dict = dict()
buffered = LineString(path).buffer(width / 1.999, int(self.steps_per_circle)) geo_dict['follow'] = geo_f
if not buffered.is_empty: if not geo_s.is_empty:
poly_buffer.append(buffered) if self.is_lpc:
if self.is_lpc is True: geo_dict['clear'] = geo_s
try:
self.apertures[last_path_aperture]['clear_geometry'].append(buffered)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = []
self.apertures[last_path_aperture]['clear_geometry'].append(buffered)
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[last_path_aperture]['solid_geometry'].append(buffered) try:
except KeyError: self.apertures[last_path_aperture]['geometry'].append(geo_dict)
self.apertures[last_path_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[last_path_aperture]['solid_geometry'].append(buffered) self.apertures[last_path_aperture]['geometry'] = []
self.apertures[last_path_aperture]['geometry'].append(geo_dict)
current_x = circular_x current_x = circular_x
current_y = circular_y current_y = circular_y
@ -3168,39 +3010,28 @@ class Gerber (Geometry):
# In case that G01 (moving) aperture is rectangular, there is no need to still create # In case that G01 (moving) aperture is rectangular, there is no need to still create
# another geo since we already created a shapely box using the start and end coordinates found in # another geo since we already created a shapely box using the start and end coordinates found in
# path variable. We do it only for other apertures than 'R' type # path variable. We do it only for other apertures than 'R' type
if self.apertures[last_path_aperture]["type"] == 'R': if self.apertures[last_path_aperture]["type"] != 'R':
pass
else:
# EOF, create shapely LineString if something still in path # EOF, create shapely LineString if something still in path
## --- Buffered ---
# this treats the case when we are storing geometry as paths
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
try:
self.apertures[current_aperture]['follow_geometry'].append(geo)
except KeyError:
self.apertures[current_aperture]['follow_geometry'] = []
self.apertures[current_aperture]['follow_geometry'].append(geo)
# this treats the case when we are storing geometry as solids
width = self.apertures[last_path_aperture]["size"] width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty: geo_f = LineString(path)
poly_buffer.append(geo) geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if self.is_lpc is True: follow_buffer.append(geo_f)
try: if not geo_s.is_empty:
self.apertures[last_path_aperture]['clear_geometry'].append(geo) poly_buffer.append(geo_s)
except KeyError:
self.apertures[last_path_aperture]['clear_geometry'] = [] geo_dict = dict()
self.apertures[last_path_aperture]['clear_geometry'].append(geo) geo_dict['follow'] = geo_f
if not geo_s.is_empty:
if self.is_lpc:
geo_dict['clear'] = geo_s
else: else:
try: geo_dict['solid'] = geo_s
self.apertures[last_path_aperture]['solid_geometry'].append(geo) try:
except KeyError: self.apertures[current_aperture]['geometry'].append(geo_dict)
self.apertures[last_path_aperture]['solid_geometry'] = [] except KeyError:
self.apertures[last_path_aperture]['solid_geometry'].append(geo) self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(geo_dict)
# TODO: make sure to keep track of units changes because right now it seems to happen in a weird way # TODO: make sure to keep track of units changes because right now it seems to happen in a weird way
# find out the conversion factor used to convert inside the self.apertures keys: size, width, height # find out the conversion factor used to convert inside the self.apertures keys: size, width, height
@ -3215,31 +3046,23 @@ class Gerber (Geometry):
global_clear_geo = [] global_clear_geo = []
for apid in self.apertures: for apid in self.apertures:
# first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo if 'geometry' in self.apertures[apid]:
if 'clear_geometry' in self.apertures[apid]: for elem in self.apertures[apid]['geometry']:
for pol in self.apertures[apid]['clear_geometry']: if 'clear' in elem:
global_clear_geo.append(pol) global_clear_geo.append(elem['clear'])
self.apertures[apid].pop('clear_geometry', None)
log.warning("Found %d clear polygons." % len(global_clear_geo)) log.warning("Found %d clear polygons." % len(global_clear_geo))
temp_geo = []
for apid in self.apertures: for apid in self.apertures:
if 'solid_geometry' in self.apertures[apid]: if 'geometry' in self.apertures[apid]:
for solid_geo in self.apertures[apid]['solid_geometry']: for elem in self.apertures[apid]['geometry']:
for clear_geo in global_clear_geo: if 'solid' in elem:
# Make sure that the clear_geo is within the solid_geo otherwise we loose for clear_geo in global_clear_geo:
# the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to # Make sure that the clear_geo is within the solid_geo otherwise we loose
# delete it # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to
if clear_geo.within(solid_geo): # delete it
solid_geo = solid_geo.difference(clear_geo) if clear_geo.within(elem['solid']):
try: elem['solid'] = elem['solid'].difference(clear_geo)
for poly in solid_geo:
temp_geo.append(poly)
except TypeError:
temp_geo.append(solid_geo)
self.apertures[apid]['solid_geometry'] = deepcopy(temp_geo)
temp_geo = []
log.warning("Polygon difference done for %d apertures." % len(self.apertures)) log.warning("Polygon difference done for %d apertures." % len(self.apertures))
for apid in self.apertures: for apid in self.apertures: