Просмотр исходного кода

Added SVG importing support to the GUI menu. See issue #179.

Juan Pablo Caram 10 лет назад
Родитель
Сommit
d3ed12e5de
4 измененных файлов с 76 добавлено и 4 удалено
  1. 24 0
      FlatCAMApp.py
  2. 5 1
      FlatCAMGUI.py
  3. 1 0
      camlib.py
  4. 46 3
      svgparse.py

+ 24 - 0
FlatCAMApp.py

@@ -430,6 +430,7 @@ class App(QtCore.QObject):
         self.ui.menufileopenexcellon.triggered.connect(self.on_fileopenexcellon)
         self.ui.menufileopenexcellon.triggered.connect(self.on_fileopenexcellon)
         self.ui.menufileopengcode.triggered.connect(self.on_fileopengcode)
         self.ui.menufileopengcode.triggered.connect(self.on_fileopengcode)
         self.ui.menufileopenproject.triggered.connect(self.on_file_openproject)
         self.ui.menufileopenproject.triggered.connect(self.on_file_openproject)
+        self.ui.menufileimportsvg.triggered.connect(self.on_file_importsvg)
         self.ui.menufilesaveproject.triggered.connect(self.on_file_saveproject)
         self.ui.menufilesaveproject.triggered.connect(self.on_file_saveproject)
         self.ui.menufilesaveprojectas.triggered.connect(self.on_file_saveprojectas)
         self.ui.menufilesaveprojectas.triggered.connect(self.on_file_saveprojectas)
         self.ui.menufilesaveprojectcopy.triggered.connect(lambda: self.on_file_saveprojectas(make_copy=True))
         self.ui.menufilesaveprojectcopy.triggered.connect(lambda: self.on_file_saveprojectas(make_copy=True))
@@ -1543,6 +1544,29 @@ class App(QtCore.QObject):
             # thread safe. The new_project()
             # thread safe. The new_project()
             self.open_project(filename)
             self.open_project(filename)
 
 
+    def on_file_importsvg(self):
+        """
+        Callback for menu item File->Import SVG.
+
+        :return: None
+        """
+        self.report_usage("on_file_importsvg")
+        App.log.debug("on_file_importsvg()")
+
+        try:
+            filename = QtGui.QFileDialog.getOpenFileName(caption="Import SVG",
+                                                         directory=self.get_last_folder())
+        except TypeError:
+            filename = QtGui.QFileDialog.getOpenFileName(caption="Import SVG")
+
+        filename = str(filename)
+
+        if str(filename) == "":
+            self.inform.emit("Open cancelled.")
+        else:
+            self.worker_task.emit({'fcn': self.import_svg,
+                                   'params': [filename]})
+
     def on_file_saveproject(self):
     def on_file_saveproject(self):
         """
         """
         Callback for menu item File->Save Project. Saves the project to
         Callback for menu item File->Save Project. Saves the project to

+ 5 - 1
FlatCAMGUI.py

@@ -28,7 +28,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
         # Recent
         # Recent
         self.recent = self.menufile.addMenu(QtGui.QIcon('share/folder16.png'), "Open recent ...")
         self.recent = self.menufile.addMenu(QtGui.QIcon('share/folder16.png'), "Open recent ...")
 
 
-        # Open gerber
+        # Open gerber ...
         self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Gerber ...', self)
         self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Gerber ...', self)
         self.menufile.addAction(self.menufileopengerber)
         self.menufile.addAction(self.menufileopengerber)
 
 
@@ -40,6 +40,10 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufileopengcode = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open G-&Code ...', self)
         self.menufileopengcode = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open G-&Code ...', self)
         self.menufile.addAction(self.menufileopengcode)
         self.menufile.addAction(self.menufileopengcode)
 
 
+        # Import SVG ...
+        self.menufileimportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Import &SVG ...', self)
+        self.menufile.addAction(self.menufileimportsvg)
+
         # Open Project ...
         # Open Project ...
         self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Project ...', self)
         self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Project ...', self)
         self.menufile.addAction(self.menufileopenproject)
         self.menufile.addAction(self.menufileopenproject)

+ 1 - 0
camlib.py

@@ -358,6 +358,7 @@ class Geometry(object):
         Imports shapes from an SVG file into the object's geometry.
         Imports shapes from an SVG file into the object's geometry.
 
 
         :param filename: Path to the SVG file.
         :param filename: Path to the SVG file.
+        :type filename: str
         :return: None
         :return: None
         """
         """
 
 

+ 46 - 3
svgparse.py

@@ -2,15 +2,24 @@
 # FlatCAM: 2D Post-processing for Manufacturing            #
 # FlatCAM: 2D Post-processing for Manufacturing            #
 # http://flatcam.org                                       #
 # http://flatcam.org                                       #
 # Author: Juan Pablo Caram (c)                             #
 # Author: Juan Pablo Caram (c)                             #
-# Date: 12/18/2015                                           #
+# Date: 12/18/2015                                         #
 # MIT Licence                                              #
 # MIT Licence                                              #
+#                                                          #
+# SVG Features supported:                                  #
+#  * Groups                                                #
+#  * Rectangles                                            #
+#  * Circles                                               #
+#  * Paths                                                 #
+#  * All transformations                                   #
+#                                                          #
+#  Reference: www.w3.org/TR/SVG/Overview.html              #
 ############################################################
 ############################################################
 
 
 import xml.etree.ElementTree as ET
 import xml.etree.ElementTree as ET
 import re
 import re
 import itertools
 import itertools
 from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
 from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
-from shapely.geometry import LinearRing, LineString
+from shapely.geometry import LinearRing, LineString, Point
 from shapely.affinity import translate, rotate, scale, skew, affine_transform
 from shapely.affinity import translate, rotate, scale, skew, affine_transform
 
 
 
 
@@ -43,10 +52,13 @@ def path2shapely(path, res=1.0):
         if isinstance(component, Arc) or \
         if isinstance(component, Arc) or \
            isinstance(component, CubicBezier) or \
            isinstance(component, CubicBezier) or \
            isinstance(component, QuadraticBezier):
            isinstance(component, QuadraticBezier):
+
+            # How many points to use in the dicrete representation.
             length = component.length(res / 10.0)
             length = component.length(res / 10.0)
             steps = int(length / res + 0.5)
             steps = int(length / res + 0.5)
             frac = 1.0 / steps
             frac = 1.0 / steps
-            print length, steps, frac
+
+            # print length, steps, frac
             for i in range(steps):
             for i in range(steps):
                 point = component.point(i * frac)
                 point = component.point(i * frac)
                 x, y = point.real, point.imag
                 x, y = point.real, point.imag
@@ -66,6 +78,16 @@ def path2shapely(path, res=1.0):
 
 
 
 
 def svgrect2shapely(rect):
 def svgrect2shapely(rect):
+    """
+    Converts an SVG rect into Shapely geometry.
+
+    :param rect: Rect Element
+    :type rect: xml.etree.ElementTree.Element
+    :return: shapely.geometry.polygon.LinearRing
+
+    :param rect:
+    :return:
+    """
     w = float(rect.get('width'))
     w = float(rect.get('width'))
     h = float(rect.get('height'))
     h = float(rect.get('height'))
     x = float(rect.get('x'))
     x = float(rect.get('x'))
@@ -76,6 +98,22 @@ def svgrect2shapely(rect):
     return LinearRing(pts)
     return LinearRing(pts)
 
 
 
 
+def svgcircle2shapely(circle):
+    """
+    Converts an SVG circle into Shapely geometry.
+
+    :param circle: Circle Element
+    :type circle: xml.etree.ElementTree.Element
+    :return: shapely.geometry.polygon.LinearRing
+    """
+    cx = float(circle.get('cx'))
+    cy = float(circle.get('cy'))
+    r = float(circle.get('r'))
+
+    # TODO: No resolution specified.
+    return Point(cx, cy).buffer(r)
+
+
 def getsvggeo(node):
 def getsvggeo(node):
     """
     """
     Extracts and flattens all geometry from an SVG node
     Extracts and flattens all geometry from an SVG node
@@ -106,6 +144,11 @@ def getsvggeo(node):
         R = svgrect2shapely(node)
         R = svgrect2shapely(node)
         geo = [R]
         geo = [R]
 
 
+    elif kind == 'circle':
+        print "***CIRCLE***"
+        C = svgcircle2shapely(node)
+        geo = [C]
+
     else:
     else:
         print "Unknown kind:", kind
         print "Unknown kind:", kind
         geo = None
         geo = None