|
@@ -43,8 +43,12 @@ class ToolPDF(FlatCAMTool):
|
|
|
|
|
|
|
|
self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)
|
|
self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)
|
|
|
|
|
|
|
|
- # detect color change; it means a new object to be created
|
|
|
|
|
- self.color_re = re.compile(r'^\s*(\d+\.?\d*) (\d+\.?\d*) (\d+\.?\d*)\s*RG$')
|
|
|
|
|
|
|
+ # detect stroke color change; it means a new object to be created
|
|
|
|
|
+ self.stroke_color_re = re.compile(r'^\s*(\d+\.?\d*) (\d+\.?\d*) (\d+\.?\d*)\s*RG$')
|
|
|
|
|
+
|
|
|
|
|
+ # detect fill color change; we check here for white color (transparent geometry);
|
|
|
|
|
+ # if detected we create an Excellon from it
|
|
|
|
|
+ self.fill_color_re = re.compile(r'^\s*(\d+\.?\d*) (\d+\.?\d*) (\d+\.?\d*)\s*rg$')
|
|
|
|
|
|
|
|
# detect 're' command
|
|
# detect 're' command
|
|
|
self.rect_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*re$')
|
|
self.rect_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*re$')
|
|
@@ -104,6 +108,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
|
|
|
|
|
self.obj_dict = dict()
|
|
self.obj_dict = dict()
|
|
|
self.pdf_parsed = ''
|
|
self.pdf_parsed = ''
|
|
|
|
|
+ self.parsed_obj_dict = dict()
|
|
|
|
|
|
|
|
# conversion factor to INCH
|
|
# conversion factor to INCH
|
|
|
self.point_to_unit_factor = 0.01388888888
|
|
self.point_to_unit_factor = 0.01388888888
|
|
@@ -151,6 +156,8 @@ class ToolPDF(FlatCAMTool):
|
|
|
new_name = filename.split('/')[-1].split('\\')[-1]
|
|
new_name = filename.split('/')[-1].split('\\')[-1]
|
|
|
self.obj_dict.clear()
|
|
self.obj_dict.clear()
|
|
|
self.pdf_parsed = ''
|
|
self.pdf_parsed = ''
|
|
|
|
|
+ self.parsed_obj_dict = {}
|
|
|
|
|
+ obj_type = 'gerber'
|
|
|
|
|
|
|
|
# the UNITS in PDF files are points and here we set the factor to convert them to real units (either MM or INCH)
|
|
# the UNITS in PDF files are points and here we set the factor to convert them to real units (either MM or INCH)
|
|
|
if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == 'MM':
|
|
if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == 'MM':
|
|
@@ -174,37 +181,96 @@ class ToolPDF(FlatCAMTool):
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
log.debug("ToolPDF.open_pdf().obj_init() --> %s" % str(e))
|
|
log.debug("ToolPDF.open_pdf().obj_init() --> %s" % str(e))
|
|
|
|
|
|
|
|
- self.obj_dict = self.parse_pdf(pdf_content=self.pdf_parsed)
|
|
|
|
|
|
|
+ self.parsed_obj_dict = self.parse_pdf(pdf_content=self.pdf_parsed)
|
|
|
|
|
|
|
|
- for k in self.obj_dict:
|
|
|
|
|
- ap_dict = deepcopy(self.obj_dict[k])
|
|
|
|
|
|
|
+ for k in self.parsed_obj_dict:
|
|
|
|
|
+ ap_dict = deepcopy(self.parsed_obj_dict[k])
|
|
|
if ap_dict:
|
|
if ap_dict:
|
|
|
- def obj_init(grb_obj, app_obj):
|
|
|
|
|
|
|
+ if k == 0:
|
|
|
|
|
+ # Excellon
|
|
|
|
|
+ obj_type = 'excellon'
|
|
|
|
|
+
|
|
|
|
|
+ new_name = new_name + "_exc"
|
|
|
|
|
+ # store the points here until reconstitution: keys are diameters and values are list of (x,y) coords
|
|
|
|
|
+ points = {}
|
|
|
|
|
+
|
|
|
|
|
+ def obj_init(exc_obj, app_obj):
|
|
|
|
|
+ # print(self.parsed_obj_dict[0])
|
|
|
|
|
+
|
|
|
|
|
+ for geo in self.parsed_obj_dict[0]['0']['solid_geometry']:
|
|
|
|
|
+ xmin, ymin, xmax, ymax = geo.bounds
|
|
|
|
|
+ center = (((xmax - xmin) / 2) + xmin, ((ymax - ymin) / 2) + ymin)
|
|
|
|
|
+
|
|
|
|
|
+ # for drill bits, even in INCH, it's enough 3 decimals
|
|
|
|
|
+ correction_factor = 0.974
|
|
|
|
|
+ dia = (xmax - xmin) * correction_factor
|
|
|
|
|
+ dia = round(dia, 3)
|
|
|
|
|
+ if dia in points:
|
|
|
|
|
+ points[dia].append(center)
|
|
|
|
|
+ else:
|
|
|
|
|
+ points[dia] = [center]
|
|
|
|
|
+
|
|
|
|
|
+ sorted_dia = sorted(points.keys())
|
|
|
|
|
+
|
|
|
|
|
+ name_tool = 0
|
|
|
|
|
+ for dia in sorted_dia:
|
|
|
|
|
+ name_tool += 1
|
|
|
|
|
+
|
|
|
|
|
+ # create tools dictionary
|
|
|
|
|
+ spec = {"C": dia}
|
|
|
|
|
+ spec['solid_geometry'] = []
|
|
|
|
|
+ exc_obj.tools[str(name_tool)] = spec
|
|
|
|
|
+
|
|
|
|
|
+ # create drill list of dictionaries
|
|
|
|
|
+ for dia_points in points:
|
|
|
|
|
+ if dia == dia_points:
|
|
|
|
|
+ for pt in points[dia_points]:
|
|
|
|
|
+ exc_obj.drills.append({'point': Point(pt), 'tool': str(name_tool)})
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ ret = exc_obj.create_geometry()
|
|
|
|
|
+ if ret == 'fail':
|
|
|
|
|
+ log.debug("Could not create geometry for Excellon object.")
|
|
|
|
|
+ return "fail"
|
|
|
|
|
+ for tool in exc_obj.tools:
|
|
|
|
|
+ if exc_obj.tools[tool]['solid_geometry']:
|
|
|
|
|
+ return
|
|
|
|
|
+ app_obj.inform.emit(_("[ERROR_NOTCL] No geometry found in file: %s") % new_name)
|
|
|
|
|
+ return "fail"
|
|
|
|
|
+ else:
|
|
|
|
|
+ # Gerber
|
|
|
|
|
+ obj_type = 'gerber'
|
|
|
|
|
|
|
|
- grb_obj.apertures = ap_dict
|
|
|
|
|
|
|
+ def obj_init(grb_obj, app_obj):
|
|
|
|
|
|
|
|
- poly_buff = []
|
|
|
|
|
- for ap in grb_obj.apertures:
|
|
|
|
|
- for k in grb_obj.apertures[ap]:
|
|
|
|
|
- if k == 'solid_geometry':
|
|
|
|
|
- poly_buff += ap_dict[ap][k]
|
|
|
|
|
|
|
+ grb_obj.apertures = ap_dict
|
|
|
|
|
|
|
|
- poly_buff = unary_union(poly_buff)
|
|
|
|
|
- poly_buff = poly_buff.buffer(0.0000001)
|
|
|
|
|
- poly_buff = poly_buff.buffer(-0.0000001)
|
|
|
|
|
|
|
+ poly_buff = []
|
|
|
|
|
+ for ap in grb_obj.apertures:
|
|
|
|
|
+ for k in grb_obj.apertures[ap]:
|
|
|
|
|
+ if k == 'solid_geometry':
|
|
|
|
|
+ poly_buff += ap_dict[ap][k]
|
|
|
|
|
|
|
|
- grb_obj.solid_geometry = deepcopy(poly_buff)
|
|
|
|
|
|
|
+ poly_buff = unary_union(poly_buff)
|
|
|
|
|
+ try:
|
|
|
|
|
+ poly_buff = poly_buff.buffer(0.0000001)
|
|
|
|
|
+ except ValueError:
|
|
|
|
|
+ pass
|
|
|
|
|
+ try:
|
|
|
|
|
+ poly_buff = poly_buff.buffer(-0.0000001)
|
|
|
|
|
+ except ValueError:
|
|
|
|
|
+ pass
|
|
|
|
|
|
|
|
- with self.app.proc_container.new(_("Opening PDF layer #%d ...") % (int(k) - 2)):
|
|
|
|
|
|
|
+ grb_obj.solid_geometry = deepcopy(poly_buff)
|
|
|
|
|
|
|
|
- ret = self.app.new_object("gerber", new_name, obj_init, autoselected=False)
|
|
|
|
|
|
|
+ with self.app.proc_container.new(_("Rendering PDF layer #%d ...") % (int(k) - 2)):
|
|
|
|
|
+
|
|
|
|
|
+ ret = self.app.new_object(obj_type, new_name, obj_init, autoselected=False)
|
|
|
if ret == 'fail':
|
|
if ret == 'fail':
|
|
|
self.app.inform.emit(_('[ERROR_NOTCL] Open PDF file failed.'))
|
|
self.app.inform.emit(_('[ERROR_NOTCL] Open PDF file failed.'))
|
|
|
return
|
|
return
|
|
|
-
|
|
|
|
|
# Register recent file
|
|
# Register recent file
|
|
|
- self.app.file_opened.emit("gerber", filename)
|
|
|
|
|
-
|
|
|
|
|
|
|
+ self.app.file_opened.emit(obj_type, filename)
|
|
|
# GUI feedback
|
|
# GUI feedback
|
|
|
self.app.inform.emit(_("[success] Opened: %s") % filename)
|
|
self.app.inform.emit(_("[success] Opened: %s") % filename)
|
|
|
|
|
|
|
@@ -233,9 +299,6 @@ class ToolPDF(FlatCAMTool):
|
|
|
offset_geo = [0, 0]
|
|
offset_geo = [0, 0]
|
|
|
scale_geo = [1, 1]
|
|
scale_geo = [1, 1]
|
|
|
|
|
|
|
|
- # initial aperture
|
|
|
|
|
- aperture = 10
|
|
|
|
|
-
|
|
|
|
|
# store the objects to be transformed into Gerbers
|
|
# store the objects to be transformed into Gerbers
|
|
|
object_dict = {}
|
|
object_dict = {}
|
|
|
|
|
|
|
@@ -245,14 +308,29 @@ class ToolPDF(FlatCAMTool):
|
|
|
# store the apertures here
|
|
# store the apertures here
|
|
|
apertures_dict = {}
|
|
apertures_dict = {}
|
|
|
|
|
|
|
|
|
|
+ # initial aperture
|
|
|
|
|
+ aperture = 10
|
|
|
|
|
+
|
|
|
|
|
+ # store the apertures with clear geometry here
|
|
|
|
|
+ # we are interested only in the circular geometry (drill holes) therefore we target only Bezier subpaths
|
|
|
|
|
+ clear_apertures_dict = dict()
|
|
|
|
|
+ # everything will be stored in the '0' aperture since we are dealing with clear polygons not strokes
|
|
|
|
|
+ clear_apertures_dict['0'] = dict()
|
|
|
|
|
+ clear_apertures_dict['0']['size'] = 0.0
|
|
|
|
|
+ clear_apertures_dict['0']['type'] = 'C'
|
|
|
|
|
+ clear_apertures_dict['0']['solid_geometry'] = []
|
|
|
|
|
+
|
|
|
# create first object
|
|
# create first object
|
|
|
object_dict[object_nr] = apertures_dict
|
|
object_dict[object_nr] = apertures_dict
|
|
|
object_nr += 1
|
|
object_nr += 1
|
|
|
|
|
|
|
|
- # on color change we create a new apertures dictionary and store the old one in a storage from where it will be
|
|
|
|
|
- # transformed into Gerber object
|
|
|
|
|
|
|
+ # on stroke color change we create a new apertures dictionary and store the old one in a storage from where
|
|
|
|
|
+ # it will be transformed into Gerber object
|
|
|
old_color = [None, None ,None]
|
|
old_color = [None, None ,None]
|
|
|
|
|
|
|
|
|
|
+ # signal that we have clear geometry and the geometry will be added to a special object_nr = 0
|
|
|
|
|
+ flag_clear_geo = False
|
|
|
|
|
+
|
|
|
line_nr = 0
|
|
line_nr = 0
|
|
|
lines = pdf_content.splitlines()
|
|
lines = pdf_content.splitlines()
|
|
|
|
|
|
|
@@ -261,9 +339,12 @@ class ToolPDF(FlatCAMTool):
|
|
|
# log.debug("line %d: %s" % (line_nr, pline))
|
|
# log.debug("line %d: %s" % (line_nr, pline))
|
|
|
|
|
|
|
|
# COLOR DETECTION / OBJECT DETECTION
|
|
# COLOR DETECTION / OBJECT DETECTION
|
|
|
- match = self.color_re.search(pline)
|
|
|
|
|
|
|
+ match = self.stroke_color_re.search(pline)
|
|
|
if match:
|
|
if match:
|
|
|
color = [float(match.group(1)), float(match.group(2)), float(match.group(3))]
|
|
color = [float(match.group(1)), float(match.group(2)), float(match.group(3))]
|
|
|
|
|
+ log.debug(
|
|
|
|
|
+ "ToolPDF.parse_pdf() --> STROKE Color change on line: %s --> RED=%f GREEN=%f BLUE=%f" %
|
|
|
|
|
+ (line_nr, color[0], color[1], color[2]))
|
|
|
|
|
|
|
|
if color[0] == old_color[0] and color[1] == old_color[1] and color[2] == old_color[2]:
|
|
if color[0] == old_color[0] and color[1] == old_color[1] and color[2] == old_color[2]:
|
|
|
# same color, do nothing
|
|
# same color, do nothing
|
|
@@ -271,9 +352,28 @@ class ToolPDF(FlatCAMTool):
|
|
|
else:
|
|
else:
|
|
|
object_dict[object_nr] = deepcopy(apertures_dict)
|
|
object_dict[object_nr] = deepcopy(apertures_dict)
|
|
|
object_nr += 1
|
|
object_nr += 1
|
|
|
|
|
+
|
|
|
object_dict[object_nr] = dict()
|
|
object_dict[object_nr] = dict()
|
|
|
- apertures_dict.clear()
|
|
|
|
|
|
|
+ apertures_dict = {}
|
|
|
old_color = copy(color)
|
|
old_color = copy(color)
|
|
|
|
|
+ # we make sure that the following geometry is added to the right storage
|
|
|
|
|
+ flag_clear_geo = False
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ # CLEAR GEOMETRY detection
|
|
|
|
|
+ match = self.fill_color_re.search(pline)
|
|
|
|
|
+ if match:
|
|
|
|
|
+ fill_color = [float(match.group(1)), float(match.group(2)), float(match.group(3))]
|
|
|
|
|
+ log.debug(
|
|
|
|
|
+ "ToolPDF.parse_pdf() --> FILL Color change on line: %s --> RED=%f GREEN=%f BLUE=%f" %
|
|
|
|
|
+ (line_nr, fill_color[0], fill_color[1], fill_color[2]))
|
|
|
|
|
+ # if the color is white we are seeing 'clear_geometry' that can't be seen. It may be that those
|
|
|
|
|
+ # geometries are actually holes from which we can make an Excellon file
|
|
|
|
|
+ if fill_color[0] == 1 and fill_color[1] == 1 and fill_color[2] == 1:
|
|
|
|
|
+ flag_clear_geo = True
|
|
|
|
|
+ else:
|
|
|
|
|
+ flag_clear_geo = False
|
|
|
|
|
+ continue
|
|
|
|
|
|
|
|
# TRANSFORMATIONS DETECTION #
|
|
# TRANSFORMATIONS DETECTION #
|
|
|
|
|
|
|
@@ -366,7 +466,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
# add the start point to subpaths
|
|
# add the start point to subpaths
|
|
|
subpath['lines'].append(start_point)
|
|
subpath['lines'].append(start_point)
|
|
|
# subpath['bezier'].append(start_point)
|
|
# subpath['bezier'].append(start_point)
|
|
|
- subpath['rectangle'].append(start_point)
|
|
|
|
|
|
|
+ # subpath['rectangle'].append(start_point)
|
|
|
current_point = start_point
|
|
current_point = start_point
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
@@ -440,7 +540,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
current_point = stop
|
|
current_point = stop
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
|
- # Draw Rectangle 're
|
|
|
|
|
|
|
+ # Draw Rectangle 're'
|
|
|
match = self.rect_re.search(pline)
|
|
match = self.rect_re.search(pline)
|
|
|
if match:
|
|
if match:
|
|
|
current_subpath = 'rectangle'
|
|
current_subpath = 'rectangle'
|
|
@@ -454,7 +554,6 @@ class ToolPDF(FlatCAMTool):
|
|
|
pt2 = (x+width, y)
|
|
pt2 = (x+width, y)
|
|
|
pt3 = (x+width, y+height)
|
|
pt3 = (x+width, y+height)
|
|
|
pt4 = (x, y+height)
|
|
pt4 = (x, y+height)
|
|
|
- # TODO: I'm not sure if rectangles are a type of subpath that close by itself
|
|
|
|
|
subpath['rectangle'] += [pt1, pt2, pt3, pt4, pt1]
|
|
subpath['rectangle'] += [pt1, pt2, pt3, pt4, pt1]
|
|
|
current_point = pt1
|
|
current_point = pt1
|
|
|
continue
|
|
continue
|
|
@@ -491,7 +590,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
path['bezier'].append(copy(subpath['bezier']))
|
|
path['bezier'].append(copy(subpath['bezier']))
|
|
|
subpath['bezier'] = []
|
|
subpath['bezier'] = []
|
|
|
elif current_subpath == 'rectangle':
|
|
elif current_subpath == 'rectangle':
|
|
|
- subpath['rectangle'].append(start_point)
|
|
|
|
|
|
|
+ # subpath['rectangle'].append(start_point)
|
|
|
# since we are closing the subpath add it to the path, a path may have chained subpaths
|
|
# since we are closing the subpath add it to the path, a path may have chained subpaths
|
|
|
path['rectangle'].append(copy(subpath['rectangle']))
|
|
path['rectangle'].append(copy(subpath['rectangle']))
|
|
|
subpath['rectangle'] = []
|
|
subpath['rectangle'] = []
|
|
@@ -566,12 +665,29 @@ class ToolPDF(FlatCAMTool):
|
|
|
path_geo.append(geo)
|
|
path_geo.append(geo)
|
|
|
subpath['rectangle'] = []
|
|
subpath['rectangle'] = []
|
|
|
|
|
|
|
|
- try:
|
|
|
|
|
- apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
- except KeyError:
|
|
|
|
|
- # in case there is no stroke width yet therefore no aperture
|
|
|
|
|
|
|
+ # store the found geometry
|
|
|
|
|
+ found_aperture = None
|
|
|
|
|
+ if apertures_dict:
|
|
|
|
|
+ for apid in apertures_dict:
|
|
|
|
|
+ # if we already have an aperture with the current size (rounded to 5 decimals)
|
|
|
|
|
+ if apertures_dict[apid]['size'] == round(applied_size, 5):
|
|
|
|
|
+ found_aperture = apid
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if found_aperture:
|
|
|
|
|
+ apertures_dict[copy(found_aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
+ found_aperture = None
|
|
|
|
|
+ else:
|
|
|
|
|
+ if str(aperture) in apertures_dict.keys():
|
|
|
|
|
+ aperture += 1
|
|
|
|
|
+ apertures_dict[str(aperture)] = {}
|
|
|
|
|
+ apertures_dict[str(aperture)]['size'] = round(applied_size, 5)
|
|
|
|
|
+ apertures_dict[str(aperture)]['type'] = 'C'
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] = []
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
+ else:
|
|
|
apertures_dict[str(aperture)] = {}
|
|
apertures_dict[str(aperture)] = {}
|
|
|
- apertures_dict[str(aperture)]['size'] = applied_size
|
|
|
|
|
|
|
+ apertures_dict[str(aperture)]['size'] = round(applied_size, 5)
|
|
|
apertures_dict[str(aperture)]['type'] = 'C'
|
|
apertures_dict[str(aperture)]['type'] = 'C'
|
|
|
apertures_dict[str(aperture)]['solid_geometry'] = []
|
|
apertures_dict[str(aperture)]['solid_geometry'] = []
|
|
|
apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
@@ -583,8 +699,8 @@ class ToolPDF(FlatCAMTool):
|
|
|
if match:
|
|
if match:
|
|
|
# scale the size here; some PDF printers apply transformation after the size is declared
|
|
# scale the size here; some PDF printers apply transformation after the size is declared
|
|
|
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
|
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
|
|
-
|
|
|
|
|
path_geo = list()
|
|
path_geo = list()
|
|
|
|
|
+
|
|
|
if current_subpath == 'lines':
|
|
if current_subpath == 'lines':
|
|
|
if path['lines']:
|
|
if path['lines']:
|
|
|
for subp in path['lines']:
|
|
for subp in path['lines']:
|
|
@@ -632,8 +748,8 @@ class ToolPDF(FlatCAMTool):
|
|
|
for subp in path['rectangle']:
|
|
for subp in path['rectangle']:
|
|
|
geo = copy(subp)
|
|
geo = copy(subp)
|
|
|
# close the subpath if it was not closed already
|
|
# close the subpath if it was not closed already
|
|
|
- if close_subpath is False:
|
|
|
|
|
- geo.append(geo[0])
|
|
|
|
|
|
|
+ if close_subpath is False and start_point is not None:
|
|
|
|
|
+ geo.append(start_point)
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
path_geo.append(geo_el)
|
|
path_geo.append(geo_el)
|
|
|
# the path was painted therefore initialize it
|
|
# the path was painted therefore initialize it
|
|
@@ -650,24 +766,35 @@ class ToolPDF(FlatCAMTool):
|
|
|
# we finished painting and also closed the path if it was the case
|
|
# we finished painting and also closed the path if it was the case
|
|
|
close_subpath = True
|
|
close_subpath = True
|
|
|
|
|
|
|
|
- try:
|
|
|
|
|
- apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
- except KeyError:
|
|
|
|
|
- # in case there is no stroke width yet therefore no aperture
|
|
|
|
|
- apertures_dict['0'] = {}
|
|
|
|
|
- apertures_dict['0']['size'] = applied_size
|
|
|
|
|
- apertures_dict['0']['type'] = 'C'
|
|
|
|
|
- apertures_dict['0']['solid_geometry'] = []
|
|
|
|
|
- apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
- continue
|
|
|
|
|
|
|
+ # if there was a fill color change we look for circular geometries from which we can make drill holes
|
|
|
|
|
+ # for the Excellon file
|
|
|
|
|
+ if flag_clear_geo is True:
|
|
|
|
|
+ # we llok for circular geometries
|
|
|
|
|
+ if current_subpath == 'bezier':
|
|
|
|
|
+ # if there are geometries in the list
|
|
|
|
|
+ if path_geo:
|
|
|
|
|
+ clear_apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
+ else:
|
|
|
|
|
+ # else, add the geometry as usual
|
|
|
|
|
+ try:
|
|
|
|
|
+ apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
+ except KeyError:
|
|
|
|
|
+ # in case there is no stroke width yet therefore no aperture
|
|
|
|
|
+ apertures_dict['0'] = {}
|
|
|
|
|
+ apertures_dict['0']['size'] = applied_size
|
|
|
|
|
+ apertures_dict['0']['type'] = 'C'
|
|
|
|
|
+ apertures_dict['0']['solid_geometry'] = []
|
|
|
|
|
+ apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
+ continue
|
|
|
|
|
|
|
|
- # fill and stroke the path
|
|
|
|
|
|
|
+ # Fill and Stroke the path
|
|
|
match = self.fill_stroke_path_re.search(pline)
|
|
match = self.fill_stroke_path_re.search(pline)
|
|
|
if match:
|
|
if match:
|
|
|
# scale the size here; some PDF printers apply transformation after the size is declared
|
|
# scale the size here; some PDF printers apply transformation after the size is declared
|
|
|
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
|
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
|
|
-
|
|
|
|
|
path_geo = list()
|
|
path_geo = list()
|
|
|
|
|
+ fill_geo = list()
|
|
|
|
|
+
|
|
|
if current_subpath == 'lines':
|
|
if current_subpath == 'lines':
|
|
|
if path['lines']:
|
|
if path['lines']:
|
|
|
# fill
|
|
# fill
|
|
@@ -677,7 +804,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(geo[0])
|
|
geo.append(geo[0])
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
for subp in path['lines']:
|
|
for subp in path['lines']:
|
|
|
geo = copy(subp)
|
|
geo = copy(subp)
|
|
@@ -692,7 +819,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(start_point)
|
|
geo.append(start_point)
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
geo = copy(subpath['lines'])
|
|
geo = copy(subpath['lines'])
|
|
|
geo = LineString(geo).buffer((float(applied_size) / 2), resolution=self.step_per_circles)
|
|
geo = LineString(geo).buffer((float(applied_size) / 2), resolution=self.step_per_circles)
|
|
@@ -711,7 +838,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(geo[0])
|
|
geo.append(geo[0])
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
for subp in path['bezier']:
|
|
for subp in path['bezier']:
|
|
|
geo = []
|
|
geo = []
|
|
@@ -728,7 +855,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(start_point)
|
|
geo.append(start_point)
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
geo = []
|
|
geo = []
|
|
|
for b in subpath['bezier']:
|
|
for b in subpath['bezier']:
|
|
@@ -746,7 +873,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(geo[0])
|
|
geo.append(geo[0])
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
for subp in path['rectangle']:
|
|
for subp in path['rectangle']:
|
|
|
geo = copy(subp)
|
|
geo = copy(subp)
|
|
@@ -761,7 +888,7 @@ class ToolPDF(FlatCAMTool):
|
|
|
if close_subpath is False:
|
|
if close_subpath is False:
|
|
|
geo.append(start_point)
|
|
geo.append(start_point)
|
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
geo_el = Polygon(geo).buffer(0.0000001, resolution=self.step_per_circles)
|
|
|
- path_geo.append(geo_el)
|
|
|
|
|
|
|
+ fill_geo.append(geo_el)
|
|
|
# stroke
|
|
# stroke
|
|
|
geo = copy(subpath['rectangle'])
|
|
geo = copy(subpath['rectangle'])
|
|
|
geo = LineString(geo).buffer((float(applied_size) / 2), resolution=self.step_per_circles)
|
|
geo = LineString(geo).buffer((float(applied_size) / 2), resolution=self.step_per_circles)
|
|
@@ -771,16 +898,53 @@ class ToolPDF(FlatCAMTool):
|
|
|
# we finished painting and also closed the path if it was the case
|
|
# we finished painting and also closed the path if it was the case
|
|
|
close_subpath = True
|
|
close_subpath = True
|
|
|
|
|
|
|
|
|
|
+ # store the found geometry for stroking the path
|
|
|
|
|
+ found_aperture = None
|
|
|
|
|
+ if apertures_dict:
|
|
|
|
|
+ for apid in apertures_dict:
|
|
|
|
|
+ # if we already have an aperture with the current size (rounded to 5 decimals)
|
|
|
|
|
+ if apertures_dict[apid]['size'] == round(applied_size, 5):
|
|
|
|
|
+ found_aperture = apid
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if found_aperture:
|
|
|
|
|
+ apertures_dict[copy(found_aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
+ found_aperture = None
|
|
|
|
|
+ else:
|
|
|
|
|
+ if str(aperture) in apertures_dict.keys():
|
|
|
|
|
+ aperture += 1
|
|
|
|
|
+ apertures_dict[str(aperture)] = {}
|
|
|
|
|
+ apertures_dict[str(aperture)]['size'] = round(applied_size, 5)
|
|
|
|
|
+ apertures_dict[str(aperture)]['type'] = 'C'
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] = []
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
+ else:
|
|
|
|
|
+ apertures_dict[str(aperture)] = {}
|
|
|
|
|
+ apertures_dict[str(aperture)]['size'] = round(applied_size, 5)
|
|
|
|
|
+ apertures_dict[str(aperture)]['type'] = 'C'
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] = []
|
|
|
|
|
+ apertures_dict[str(aperture)]['solid_geometry'] += path_geo
|
|
|
|
|
+
|
|
|
|
|
+ # store the found geometry for filling the path
|
|
|
try:
|
|
try:
|
|
|
- apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
|
|
+ apertures_dict['0']['solid_geometry'] += fill_geo
|
|
|
except KeyError:
|
|
except KeyError:
|
|
|
# in case there is no stroke width yet therefore no aperture
|
|
# in case there is no stroke width yet therefore no aperture
|
|
|
apertures_dict['0'] = {}
|
|
apertures_dict['0'] = {}
|
|
|
- apertures_dict['0']['size'] = applied_size
|
|
|
|
|
|
|
+ apertures_dict['0']['size'] = round(applied_size, 5)
|
|
|
apertures_dict['0']['type'] = 'C'
|
|
apertures_dict['0']['type'] = 'C'
|
|
|
apertures_dict['0']['solid_geometry'] = []
|
|
apertures_dict['0']['solid_geometry'] = []
|
|
|
- apertures_dict['0']['solid_geometry'] += path_geo
|
|
|
|
|
|
|
+ apertures_dict['0']['solid_geometry'] += fill_geo
|
|
|
|
|
+
|
|
|
continue
|
|
continue
|
|
|
|
|
+
|
|
|
|
|
+ # tidy up. copy the current aperture dict to the object dict but only if it is not empty
|
|
|
|
|
+ if apertures_dict:
|
|
|
|
|
+ object_dict[object_nr] = deepcopy(apertures_dict)
|
|
|
|
|
+
|
|
|
|
|
+ if clear_apertures_dict['0']['solid_geometry']:
|
|
|
|
|
+ object_dict[0] = deepcopy(clear_apertures_dict)
|
|
|
|
|
+
|
|
|
return object_dict
|
|
return object_dict
|
|
|
|
|
|
|
|
def bezier_to_points(self, start, c1, c2, stop):
|
|
def bezier_to_points(self, start, c1, c2, stop):
|