diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 691c33a6..dfbbf718 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -1308,84 +1308,87 @@ class FlatCAMGerber(FlatCAMObj, Gerber): for geo_elem in self.apertures['0']['geometry']: if 'solid' in geo_elem: geo = geo_elem['solid'] - gerber_code += 'G36*\n' - geo_coords = list(geo.exterior.coords) - # first command is a move with pen-up D02 at the beginning of the geo - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - for coord in geo_coords[1:]: + if not geo.is_empty: + gerber_code += 'G36*\n' + geo_coords = list(geo.exterior.coords) + # first command is a move with pen-up D02 at the beginning of the geo if g_zeros == 'T': - x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) - gerber_code += 'D02*\n' - gerber_code += 'G37*\n' - - clear_list = list(geo.interiors) - if clear_list: - gerber_code += '%LPC*%\n' - for clear_geo in clear_list: - gerber_code += 'G36*\n' - geo_coords = list(clear_geo.coords) - - # first command is a move with pen-up D02 at the beginning of the geo + for coord in geo_coords[1:]: if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, yform=y_formatted) - for coord in geo_coords[1:]: + gerber_code += 'D02*\n' + gerber_code += 'G37*\n' + + clear_list = list(geo.interiors) + if clear_list: + gerber_code += '%LPC*%\n' + for clear_geo in clear_list: + gerber_code += 'G36*\n' + geo_coords = list(clear_geo.coords) + + # first command is a move with pen-up D02 at the beginning of the geo if g_zeros == 'T': - x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = lz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) - gerber_code += 'D02*\n' - gerber_code += 'G37*\n' - gerber_code += '%LPD*%\n' + for coord in geo_coords[1:]: + if g_zeros == 'T': + x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + gerber_code += 'D02*\n' + gerber_code += 'G37*\n' + gerber_code += '%LPD*%\n' if 'clear' in geo_elem: geo = geo_elem['clear'] - - gerber_code += '%LPC*%\n' - gerber_code += 'G36*\n' - geo_coords = list(geo.exterior.coords) - # first command is a move with pen-up D02 at the beginning of the geo - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - for coord in geo_coords[1:]: + if not geo.is_empty: + gerber_code += '%LPC*%\n' + gerber_code += 'G36*\n' + geo_coords = list(geo.exterior.coords) + # first command is a move with pen-up D02 at the beginning of the geo if g_zeros == 'T': - x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, yform=y_formatted) - gerber_code += 'D02*\n' - gerber_code += 'G37*\n' - gerber_code += '%LPD*%\n' + for coord in geo_coords[1:]: + if g_zeros == 'T': + x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + gerber_code += 'D02*\n' + gerber_code += 'G37*\n' + gerber_code += '%LPD*%\n' for apid in self.apertures: if apid == '0': @@ -1396,75 +1399,78 @@ class FlatCAMGerber(FlatCAMObj, Gerber): for geo_elem in self.apertures[apid]['geometry']: if 'follow' in geo_elem: geo = geo_elem['follow'] - if geo.is_empty: - continue - - if isinstance(geo, Point): - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo.x, geo.y, factor) - gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo.x, geo.y, factor) - gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, - yform=y_formatted) - else: - geo_coords = list(geo.coords) - # first command is a move with pen-up D02 at the beginning of the geo - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - for coord in geo_coords[1:]: + if not geo.is_empty: + if isinstance(geo, Point): if g_zeros == 'T': - x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format(geo.x, geo.y, factor) + gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = lz_format(geo.x, geo.y, factor) + gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, yform=y_formatted) - # gerber_code += "D02*\n" + else: + geo_coords = list(geo.coords) + # first command is a move with pen-up D02 at the beginning of the geo + if g_zeros == 'T': + x_formatted, y_formatted = tz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + yform=y_formatted) + for coord in geo_coords[1:]: + if g_zeros == 'T': + x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + # gerber_code += "D02*\n" if 'clear' in geo_elem: gerber_code += '%LPC*%\n' geo = geo_elem['clear'] - if isinstance(geo, Point): - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo.x, geo.y, factor) - gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo.x, geo.y, factor) - gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, - yform=y_formatted) - else: - geo_coords = list(geo.coords) - # first command is a move with pen-up D02 at the beginning of the geo - if g_zeros == 'T': - x_formatted, y_formatted = tz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - else: - x_formatted, y_formatted = lz_format(geo_coords[0][0], geo_coords[0][1], factor) - gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, - yform=y_formatted) - for coord in geo_coords[1:]: + if not geo.is_empty: + if isinstance(geo, Point): if g_zeros == 'T': - x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + x_formatted, y_formatted = tz_format(geo.x, geo.y, factor) + gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, yform=y_formatted) else: - x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) - gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, - yform=y_formatted) - # gerber_code += "D02*\n" - gerber_code += '%LPD*%\n' + x_formatted, y_formatted = lz_format(geo.x, geo.y, factor) + gerber_code += "X{xform}Y{yform}D03*\n".format(xform=x_formatted, + yform=y_formatted) + else: + geo_coords = list(geo.coords) + # first command is a move with pen-up D02 at the beginning of the geo + if g_zeros == 'T': + x_formatted, y_formatted = tz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format( + geo_coords[0][0], geo_coords[0][1], factor) + gerber_code += "X{xform}Y{yform}D02*\n".format(xform=x_formatted, + yform=y_formatted) + for coord in geo_coords[1:]: + if g_zeros == 'T': + x_formatted, y_formatted = tz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + else: + x_formatted, y_formatted = lz_format(coord[0], coord[1], factor) + gerber_code += "X{xform}Y{yform}D01*\n".format(xform=x_formatted, + yform=y_formatted) + # gerber_code += "D02*\n" + gerber_code += '%LPD*%\n' except Exception as e: log.debug("FlatCAMObj.FlatCAMGerber.export_gerber() --> %s" % str(e)) diff --git a/README.md b/README.md index 1d13e7da..ed2d5f2b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ CAD program, and create G-Code for Isolation routing. - Gerber Editor: fixed the Poligonize Tool to work with new geometric structure and took care of a special case - Gerber Export is fixed to work with the new Gerber object data structure and it now works also for Gerber objects edited in Gerber Editor - Gerber Editor: fixed units conversion for obj.apertures keys that require it +- camlib Gerber parser - made sure that we don't loose goemetry in regions +- Gerber Editor - made sure that for some tools the added geometry is clean (the coordinates are non repeating) +- covered some possible issues in Gerber Export 12.05.2019 diff --git a/camlib.py b/camlib.py index 709aacfb..2084c186 100644 --- a/camlib.py +++ b/camlib.py @@ -2575,27 +2575,28 @@ class Gerber (Geometry): self.apertures['0']['size'] = 0.0 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; we have to add the current # geo to the poly_buffer otherwise we loose it - # if current_operation_code == 2: - # print(path) - # geo_dict = dict() - # if geo_f: - # if not geo_f.is_empty: - # follow_buffer.append(geo_f) - # geo_dict['follow'] = geo_f - # if geo_s: - # if not geo_s.is_empty: - # poly_buffer.append(geo_s) - # if self.is_lpc is True: - # geo_dict['clear'] = geo_s - # else: - # geo_dict['solid'] = geo_s - # - # if geo_s or geo_f: - # self.apertures['0']['geometry'].append(deepcopy(geo_dict)) - # - # continue + if current_operation_code == 2: + if len(path) == 1: + # this means that the geometry was prepared previously and we just need to add it + geo_dict = dict() + if geo_f: + if not geo_f.is_empty: + follow_buffer.append(geo_f) + geo_dict['follow'] = geo_f + if geo_s: + if not geo_s.is_empty: + poly_buffer.append(geo_s) + if self.is_lpc is True: + geo_dict['clear'] = geo_s + else: + geo_dict['solid'] = geo_s + + if geo_s or geo_f: + self.apertures['0']['geometry'].append(deepcopy(geo_dict)) + + path = [[current_x, current_y]] # Start new path # Only one path defines region? # This can happen if D02 happened before G37 and diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index 3628b71e..9d83acf8 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -767,6 +767,9 @@ class FCPoligonize(FCShapeTool): current_storage = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['geometry'] if isinstance(fused_geo, MultiPolygon): for geo in fused_geo: + # clean-up the geo + geo = geo.buffer(0) + if len(geo.interiors) == 0: try: current_storage = self.draw_app.storage_dict['0']['geometry'] @@ -778,6 +781,9 @@ class FCPoligonize(FCShapeTool): new_el['follow'] = geo.exterior self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(deepcopy(new_el))) else: + # clean-up the geo + fused_geo = fused_geo.buffer(0) + if len(fused_geo.interiors) == 0 and len(exterior_geo) == 1: try: current_storage = self.draw_app.storage_dict['0']['geometry'] @@ -1118,7 +1124,7 @@ class FCTrack(FCRegion): new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val) new_geo_el['follow'] = Point(self.temp_points) else: - new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val) + new_geo_el['solid'] = (LineString(self.temp_points).buffer(self.buf_val)).buffer(0) new_geo_el['follow'] = LineString(self.temp_points) self.geometry = DrawToolShape(new_geo_el) @@ -1134,7 +1140,12 @@ class FCTrack(FCRegion): def click(self, point): self.draw_app.in_action = True - self.points.append(point) + try: + if point != self.points[-1]: + self.points.append(point) + except IndexError: + self.points.append(point) + new_geo_el = dict() if len(self.temp_points) == 1: