diff --git a/FlatCAMApp.py b/FlatCAMApp.py index b4114bc0..2538919f 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -10097,6 +10097,11 @@ class App(QtCore.QObject): file_string = StringIO(obj.source_file) time_string = "{:%A, %d %B %Y at %H:%M}".format(datetime.now()) + if file_string.getvalue() == '': + self.inform.emit('[ERROR_NOTCL] %s' % + _("Save cancelled because source file is empty. Try to export the Gerber file.")) + return 'fail' + try: with open(filename, 'w') as file: file.writelines('G04*\n') @@ -10468,11 +10473,10 @@ class App(QtCore.QObject): if geo_type is None or geo_type == "geometry": obj_type = "geometry" elif geo_type == "gerber": - obj_type = geo_type + obj_type = "gerber" else: self.inform.emit('[ERROR_NOTCL] %s' % - _("Not supported type is picked as parameter. " - "Only Geometry and Gerber are supported")) + _("Not supported type is picked as parameter. Only Geometry and Gerber are supported")) return units = self.defaults['units'].upper() @@ -10480,6 +10484,7 @@ class App(QtCore.QObject): def obj_init(geo_obj, app_obj): geo_obj.import_svg(filename, obj_type, units=units) geo_obj.multigeo = False + geo_obj.source_file = self.export_gerber(obj_name=name, filename=None, local_use=geo_obj, use_thread=False) with self.proc_container.new(_("Importing SVG")) as proc: diff --git a/README.md b/README.md index 474785eb..847090de 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing. 2.12.2019 - fixed issue #343; updated the Image Tool +- improvements in Importing SVG as Gerber - added an automatic source generation (it is not infallible) +- a hack to import correctly the QRCode exported as SVG from FlatCAM 28.11.2019 diff --git a/camlib.py b/camlib.py index 14515f4c..aede3e53 100644 --- a/camlib.py +++ b/camlib.py @@ -1016,17 +1016,14 @@ class Geometry(object): # Add to object if self.solid_geometry is None: - self.solid_geometry = [] + self.solid_geometry = list() if type(self.solid_geometry) is list: - # self.solid_geometry.append(cascaded_union(geos)) if type(geos) is list: self.solid_geometry += geos else: self.solid_geometry.append(geos) else: # It's shapely geometry - # self.solid_geometry = cascaded_union([self.solid_geometry, - # cascaded_union(geos)]) self.solid_geometry = [self.solid_geometry, geos] # flatten the self.solid_geometry list for import_svg() to import SVG as Gerber @@ -1034,7 +1031,7 @@ class Geometry(object): geos_text = getsvgtext(svg_root, object_type, units=units) if geos_text is not None: - geos_text_f = [] + geos_text_f = list() if flip: # Change origin to bottom left for i in geos_text: diff --git a/flatcamParsers/ParseGerber.py b/flatcamParsers/ParseGerber.py index e843260e..dfc27c58 100644 --- a/flatcamParsers/ParseGerber.py +++ b/flatcamParsers/ParseGerber.py @@ -9,13 +9,15 @@ import traceback from copy import deepcopy import sys -from shapely.ops import cascaded_union +from shapely.ops import cascaded_union, unary_union from shapely.geometry import Polygon, MultiPolygon, LineString, Point import shapely.affinity as affinity from shapely.geometry import box as shply_box -import FlatCAMTranslation as fcTranslate +from lxml import etree as ET +from flatcamParsers.ParseSVG import * +import FlatCAMTranslation as fcTranslate import gettext import builtins @@ -784,7 +786,7 @@ class Gerber(Geometry): self.apertures['0'] = {} self.apertures['0']['type'] = 'REG' self.apertures['0']['size'] = 0.0 - self.apertures['0']['geometry'] = [] + self.apertures['0']['geometry'] = list() # 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 @@ -1635,6 +1637,87 @@ class Gerber(Geometry): self.scale(factor, factor) return factor + def import_svg(self, filename, object_type='gerber', flip=True, units='MM'): + """ + Imports shapes from an SVG file into the object's geometry. + + :param filename: Path to the SVG file. + :type filename: str + :param object_type: parameter passed further along + :param flip: Flip the vertically. + :type flip: bool + :param units: FlatCAM units + :return: None + """ + + log.debug("flatcamParsers.ParseGerber.Gerber.import_svg()") + + # Parse into list of shapely objects + svg_tree = ET.parse(filename) + svg_root = svg_tree.getroot() + + # Change origin to bottom left + # h = float(svg_root.get('height')) + # w = float(svg_root.get('width')) + h = svgparselength(svg_root.get('height'))[0] # TODO: No units support yet + + geos = getsvggeo(svg_root, 'gerber') + if flip: + geos = [translate(scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos] + + # Add to object + if self.solid_geometry is None: + self.solid_geometry = list() + + # if type(self.solid_geometry) == list: + # if type(geos) == list: + # self.solid_geometry += geos + # else: + # self.solid_geometry.append(geos) + # else: # It's shapely geometry + # self.solid_geometry = [self.solid_geometry, geos] + + if type(geos) == list: + # HACK for importing QRCODE exported by FlatCAM + if len(geos) == 1: + geo_qrcode = list() + geo_qrcode.append(Polygon(geos[0].exterior)) + for i_el in geos[0].interiors: + geo_qrcode.append(Polygon(i_el).buffer(0)) + for poly in geo_qrcode: + geos.append(poly) + + if type(self.solid_geometry) == list: + self.solid_geometry += geos + else: + geos.append(self.solid_geometry) + self.solid_geometry = geos + else: + if type(self.solid_geometry) == list: + self.solid_geometry.append(geos) + else: + self.solid_geometry = [self.solid_geometry, geos] + + # flatten the self.solid_geometry list for import_svg() to import SVG as Gerber + self.solid_geometry = list(self.flatten_list(self.solid_geometry)) + + try: + __ = iter(self.solid_geometry) + except TypeError: + self.solid_geometry = [self.solid_geometry] + + if '0' not in self.apertures: + self.apertures['0'] = dict() + self.apertures['0']['type'] = 'REG' + self.apertures['0']['size'] = 0.0 + self.apertures['0']['geometry'] = list() + + for pol in self.solid_geometry: + new_el = dict() + new_el['solid'] = pol + new_el['follow'] = pol.exterior + self.apertures['0']['geometry'].append(deepcopy(new_el)) + def scale(self, xfactor, yfactor=None, point=None): """ Scales the objects' geometry on the XY plane by a given factor. diff --git a/flatcamParsers/ParseSVG.py b/flatcamParsers/ParseSVG.py index 7ed6708b..2aa5db2d 100644 --- a/flatcamParsers/ParseSVG.py +++ b/flatcamParsers/ParseSVG.py @@ -141,7 +141,6 @@ def path2shapely(path, object_type, res=1.0): coords.append(line.coords[1]) geo_element = Polygon(coords) geometry.append(geo_element) - return geometry @@ -306,7 +305,7 @@ def getsvggeo(node, object_type, root=None): root = node kind = re.search('(?:\{.*\})?(.*)$', node.tag).group(1) - geo = [] + geo = list() # Recurse if len(node) > 0: