chiark / gitweb /
Add more 2D drawing code. Unused, but still, I have plans. (And all developed in...
authordaid <daid303@gmail.com>
Tue, 1 Oct 2013 09:59:05 +0000 (11:59 +0200)
committerdaid <daid303@gmail.com>
Tue, 1 Oct 2013 09:59:05 +0000 (11:59 +0200)
Cura/util/drawingLoader/__init__.py [new file with mode: 0644]
Cura/util/drawingLoader/drawing.py [new file with mode: 0644]
Cura/util/drawingLoader/dxf.py [new file with mode: 0644]
Cura/util/drawingLoader/svg.py [moved from Cura/util/svg.py with 69% similarity]

diff --git a/Cura/util/drawingLoader/__init__.py b/Cura/util/drawingLoader/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Cura/util/drawingLoader/drawing.py b/Cura/util/drawingLoader/drawing.py
new file mode 100644 (file)
index 0000000..d9822f2
--- /dev/null
@@ -0,0 +1,184 @@
+from __future__ import absolute_import
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
+
+import math
+import numpy
+
+class Path(object):
+       LINE = 0
+       ARC = 1
+       CURVE = 2
+
+       def __init__(self, x, y, matrix=numpy.matrix(numpy.identity(3, numpy.float64))):
+               self._matrix = matrix
+               self._startPoint = complex(x, y)
+               self._points = []
+               self._isClosed = False
+
+       def addLineTo(self, x, y):
+               self._points.append({'type': Path.LINE, 'p': complex(x, y)})
+
+       def addArcTo(self, x, y, rot, rx, ry, large, sweep):
+               self._points.append({
+                       'type': Path.ARC,
+                       'p': complex(x, y),
+                       'rot': rot,
+                       'radius': complex(rx, ry),
+                       'large': large,
+                       'sweep': sweep
+               })
+
+       def addCurveTo(self, x, y, cp1x, cp1y, cp2x, cp2y):
+               self._points.append({
+                       'type': Path.CURVE,
+                       'p': complex(x, y),
+                       'cp1': complex(cp1x, cp1y),
+                       'cp2': complex(cp2x, cp2y)
+               })
+
+       def isClosed(self):
+               return self._isClosed
+
+       def checkClosed(self):
+               if abs(self._points[-1]['p'] - self._startPoint) < 0.001:
+                       self._isClosed = True
+
+       def closePath(self):
+               self._points.append({'type': Path.LINE, 'p': self._startPoint})
+               self._isClosed = True
+
+       def getPoints(self, accuracy = 1):
+               pointList = [self._m(self._startPoint)]
+               p1 = self._startPoint
+               for p in self._points:
+                       if p['type'] == Path.LINE:
+                               p1 = p['p']
+                               pointList.append(self._m(p1))
+                       elif p['type'] == Path.ARC:
+                               p2 = p['p']
+                               rot = math.radians(p['rot'])
+                               r = p['radius']
+
+                               #http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
+                               diff = (p1 - p2) / 2
+                               p1alt = diff #TODO: apply rot
+                               p2alt = -diff #TODO: apply rot
+                               rx2 = r.real*r.real
+                               ry2 = r.imag*r.imag
+                               x1alt2 = p1alt.real*p1alt.real
+                               y1alt2 = p1alt.imag*p1alt.imag
+
+                               f = x1alt2 / rx2 + y1alt2 / ry2
+                               if f >= 1.0:
+                                       r *= math.sqrt(f+0.000001)
+                                       rx2 = r.real*r.real
+                                       ry2 = r.imag*r.imag
+
+                               f = math.sqrt((rx2*ry2 - rx2*y1alt2 - ry2*x1alt2) / (rx2*y1alt2+ry2*x1alt2))
+                               if p['large'] == p['sweep']:
+                                       f = -f
+                               cAlt = f * complex(r.real*p1alt.imag/r.imag, -r.imag*p1alt.real/r.real)
+
+                               c = cAlt + (p1 + p2) / 2 #TODO: apply rot
+
+                               a1 = math.atan2((p1alt.imag - cAlt.imag) / r.imag, (p1alt.real - cAlt.real) / r.real)
+                               a2 = math.atan2((p2alt.imag - cAlt.imag) / r.imag, (p2alt.real - cAlt.real) / r.real)
+
+                               large = abs(a2 - a1) > math.pi
+                               if large != p['large']:
+                                       if a1 < a2:
+                                               a1 += math.pi * 2
+                                       else:
+                                               a2 += math.pi * 2
+
+                               pCenter = self._m(c + complex(math.cos(a1 + 0.5*(a2-a1)) * r.real, math.sin(a1 + 0.5*(a2-a1)) * r.imag))
+                               dist = abs(pCenter - self._m(p1)) + abs(pCenter - self._m(p2))
+                               segments = int(dist / accuracy) + 1
+                               for n in xrange(1, segments):
+                                       pointList.append(self._m(c + complex(math.cos(a1 + n*(a2-a1)/segments) * r.real, math.sin(a1 + n*(a2-a1)/segments) * r.imag)))
+
+                               pointList.append(self._m(p2))
+                               p1 = p2
+                       elif p['type'] == Path.CURVE:
+                               p1_ = self._m(p1)
+                               p2 = self._m(p['p'])
+                               cp1 = self._m(p['cp1'])
+                               cp2 = self._m(p['cp2'])
+
+                               pCenter = p1_*0.5*0.5*0.5 + cp1*3.0*0.5*0.5*0.5 + cp2*3.0*0.5*0.5*0.5 + p2*0.5*0.5*0.5
+                               dist = abs(pCenter - p1_) + abs(pCenter - p2)
+                               segments = int(dist / accuracy) + 1
+                               for n in xrange(1, segments):
+                                       f = n / float(segments)
+                                       g = 1.0-f
+                                       point = p1_*g*g*g + cp1*3.0*g*g*f + cp2*3.0*g*f*f + p2*f*f*f
+                                       pointList.append(point)
+
+                               pointList.append(p2)
+                               p1 = p['p']
+
+               return pointList
+
+       #getSVGPath returns an SVG path string. Ths path string is not perfect when matrix transformations are involved.
+       def getSVGPath(self):
+               p0 = self._m(self._startPoint)
+               ret = 'M %f %f ' % (p0.real, p0.imag)
+               for p in self._points:
+                       if p['type'] == Path.LINE:
+                               p0 = self._m(p['p'])
+                               ret += 'L %f %f' % (p0.real, p0.imag)
+                       elif p['type'] == Path.ARC:
+                               p0 = self._m(p['p'])
+                               radius = p['radius']
+                               ret += 'A %f %f 0 %d %d %f %f' % (radius.real, radius.imag, 1 if p['large'] else 0, 1 if p['sweep'] else 0, p0.real, p0.imag)
+                       elif p['type'] == Path.CURVE:
+                               p0 = self._m(p['p'])
+                               cp1 = self._m(p['cp1'])
+                               cp2 = self._m(p['cp2'])
+                               ret += 'C %f %f %f %f %f %f' % (cp1.real, cp1.imag, cp2.real, cp2.imag, p0.real, p0.imag)
+
+               return ret
+
+       def _m(self, p):
+               tmp = numpy.matrix([p.real, p.imag, 1], numpy.float64) * self._matrix
+               return complex(tmp[0,0], tmp[0,1])
+
+def saveAsHtml(paths, filename):
+       f = open(filename, "w")
+
+       posMax = complex(-1000, -1000)
+       posMin = complex( 1000,  1000)
+       for path in paths.paths:
+               points = path.getPoints()
+               for p in points:
+                       if p.real > posMax.real:
+                               posMax = complex(p.real, posMax.imag)
+                       if p.imag > posMax.imag:
+                               posMax = complex(posMax.real, p.imag)
+                       if p.real < posMin.real:
+                               posMin = complex(p.real, posMin.imag)
+                       if p.imag < posMin.imag:
+                               posMin = complex(posMin.real, p.imag)
+
+       f.write("<!DOCTYPE html><html><body>\n")
+       f.write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style='width:%dpx;height:%dpx'>\n" % ((posMax - posMin).real, (posMax - posMin).imag))
+       f.write("<g fill-rule='evenodd' style=\"fill: gray; stroke:black;stroke-width:2\">\n")
+       f.write("<path d=\"")
+       for path in paths.paths:
+               points = path.getPoints()
+               f.write("M %f %f " % (points[0].real - posMin.real, points[0].imag - posMin.imag))
+               for point in points[1:]:
+                       f.write("L %f %f " % (point.real - posMin.real, point.imag - posMin.imag))
+       f.write("\"/>")
+       f.write("</g>\n")
+
+       f.write("<g style=\"fill: none; stroke:red;stroke-width:1\">\n")
+       f.write("<path d=\"")
+       for path in paths.paths:
+               f.write(path.getSVGPath())
+       f.write("\"/>")
+       f.write("</g>\n")
+
+       f.write("</svg>\n")
+       f.write("</body></html>")
+       f.close()
diff --git a/Cura/util/drawingLoader/dxf.py b/Cura/util/drawingLoader/dxf.py
new file mode 100644 (file)
index 0000000..3915572
--- /dev/null
@@ -0,0 +1,73 @@
+from __future__ import absolute_import
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
+
+import math
+import re
+import sys
+import numpy
+from xml.etree import ElementTree
+
+from Cura.util.drawingLoader import drawing
+
+class DXF(object):
+       def __init__(self, filename):
+               self.paths = []
+               self._lastLine = None
+               self._polyLine = None
+
+               entityType = 'UNKNOWN'
+               sectionName = 'UNKNOWN'
+               activeObject = None
+               f = open(filename, "r")
+               while True:
+                       groupCode = f.readline().strip()
+                       if groupCode == '':
+                               break
+                       groupCode = int(groupCode)
+                       value = f.readline().strip()
+                       if groupCode == 0:
+                               if sectionName == 'ENTITIES':
+                                       self._checkForNewPath(entityType, activeObject)
+                               entityType = value
+                               activeObject = {}
+                       elif entityType == 'SECTION':
+                               if groupCode == 2:
+                                       sectionName = value
+                       else:
+                               activeObject[groupCode] = value
+               if sectionName == 'ENTITIES':
+                       self._checkForNewPath(entityType, activeObject)
+               f.close()
+
+               for path in self.paths:
+                       if not path.isClosed():
+                               path.checkClosed()
+
+       def _checkForNewPath(self, type, obj):
+               if type == 'LINE':
+                       if self._lastLine is not None and self._lastLinePoint == complex(float(obj[10]), float(obj[20])):
+                               self._lastLine.addLineTo(float(obj[11]), float(obj[21]))
+                       else:
+                               p = drawing.Path(float(obj[10]), float(obj[20]))
+                               p.addLineTo(float(obj[11]), float(obj[21]))
+                               self.paths.append(p)
+                               self._lastLine = p
+                       self._lastLinePoint = complex(float(obj[11]), float(obj[21]))
+               elif type == 'POLYLINE':
+                       self._polyLine = None
+               elif type == 'VERTEX':
+                       if self._polyLine is None:
+                               self._polyLine = drawing.Path(float(obj[10]), float(obj[20]))
+                               self.paths.append(self._polyLine)
+                       else:
+                               self._polyLine.addLineTo(float(obj[10]), float(obj[20]))
+               else:
+                       print type
+
+if __name__ == '__main__':
+       for n in xrange(1, len(sys.argv)):
+               print 'File: %s' % (sys.argv[n])
+               dxf = DXF(sys.argv[n])
+
+       drawing.saveAsHtml(dxf, "test_export.html")
+
similarity index 69%
rename from Cura/util/svg.py
rename to Cura/util/drawingLoader/svg.py
index b91fcc3c51f4184d1dee4033a118ad194676ff63..e57b35333ace4ea8664f921c016124ed2bca4bff 100644 (file)
@@ -7,6 +7,8 @@ import sys
 import numpy
 from xml.etree import ElementTree
 
+from Cura.util.drawingLoader import drawing
+
 def applyTransformString(matrix, transform):
        while transform != '':
                if transform[0] == ',':
@@ -50,139 +52,6 @@ def toFloat(f):
        f = re.search('^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?', f).group(0)
        return float(f)
 
-class Path(object):
-       LINE = 0
-       ARC = 1
-       CURVE = 2
-
-       def __init__(self, x, y, matrix):
-               self._matrix = matrix
-               self._relMatrix = numpy.matrix([[matrix[0,0],matrix[0,1]], [matrix[1,0],matrix[1,1]]])
-               self._startPoint = complex(x, y)
-               self._points = []
-
-       def addLineTo(self, x, y):
-               self._points.append({'type': Path.LINE, 'p': complex(x, y)})
-
-       def addArcTo(self, x, y, rot, rx, ry, large, sweep):
-               self._points.append({
-                       'type': Path.ARC,
-                       'p': complex(x, y),
-                       'rot': rot,
-                       'radius': complex(rx, ry),
-                       'large': large,
-                       'sweep': sweep
-               })
-
-       def addCurveTo(self, x, y, cp1x, cp1y, cp2x, cp2y):
-               self._points.append({
-                       'type': Path.CURVE,
-                       'p': complex(x, y),
-                       'cp1': complex(cp1x, cp1y),
-                       'cp2': complex(cp2x, cp2y)
-               })
-
-       def closePath(self):
-               self._points.append({'type': Path.LINE, 'p': self._startPoint})
-
-       def getPoints(self, accuracy = 1):
-               pointList = [self._m(self._startPoint)]
-               p1 = self._startPoint
-               for p in self._points:
-                       if p['type'] == Path.LINE:
-                               p1 = p['p']
-                               pointList.append(self._m(p1))
-                       elif p['type'] == Path.ARC:
-                               p2 = p['p']
-                               rot = math.radians(p['rot'])
-                               r = p['radius']
-
-                               #http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
-                               diff = (p1 - p2) / 2
-                               p1alt = diff #TODO: apply rot
-                               p2alt = -diff #TODO: apply rot
-                               rx2 = r.real*r.real
-                               ry2 = r.imag*r.imag
-                               x1alt2 = p1alt.real*p1alt.real
-                               y1alt2 = p1alt.imag*p1alt.imag
-
-                               f = x1alt2 / rx2 + y1alt2 / ry2
-                               if f >= 1.0:
-                                       r *= math.sqrt(f+0.000001)
-                                       rx2 = r.real*r.real
-                                       ry2 = r.imag*r.imag
-
-                               f = math.sqrt((rx2*ry2 - rx2*y1alt2 - ry2*x1alt2) / (rx2*y1alt2+ry2*x1alt2))
-                               if p['large'] == p['sweep']:
-                                       f = -f
-                               cAlt = f * complex(r.real*p1alt.imag/r.imag, -r.imag*p1alt.real/r.real)
-
-                               c = cAlt + (p1 + p2) / 2 #TODO: apply rot
-
-                               a1 = math.atan2((p1alt.imag - cAlt.imag) / r.imag, (p1alt.real - cAlt.real) / r.real)
-                               a2 = math.atan2((p2alt.imag - cAlt.imag) / r.imag, (p2alt.real - cAlt.real) / r.real)
-
-                               large = abs(a2 - a1) > math.pi
-                               if large != p['large']:
-                                       if a1 < a2:
-                                               a1 += math.pi * 2
-                                       else:
-                                               a2 += math.pi * 2
-
-                               pCenter = self._m(c + complex(math.cos(a1 + 0.5*(a2-a1)) * r.real, math.sin(a1 + 0.5*(a2-a1)) * r.imag))
-                               dist = abs(pCenter - self._m(p1)) + abs(pCenter - self._m(p2))
-                               segments = int(dist / accuracy) + 1
-                               for n in xrange(1, segments):
-                                       pointList.append(self._m(c + complex(math.cos(a1 + n*(a2-a1)/segments) * r.real, math.sin(a1 + n*(a2-a1)/segments) * r.imag)))
-
-                               pointList.append(self._m(p2))
-                               p1 = p2
-                       elif p['type'] == Path.CURVE:
-                               p1_ = self._m(p1)
-                               p2 = self._m(p['p'])
-                               cp1 = self._m(p['cp1'])
-                               cp2 = self._m(p['cp2'])
-
-                               pCenter = p1_*0.5*0.5*0.5 + cp1*3.0*0.5*0.5*0.5 + cp2*3.0*0.5*0.5*0.5 + p2*0.5*0.5*0.5
-                               dist = abs(pCenter - p1_) + abs(pCenter - p2)
-                               segments = int(dist / accuracy) + 1
-                               for n in xrange(1, segments):
-                                       f = n / float(segments)
-                                       g = 1.0-f
-                                       point = p1_*g*g*g + cp1*3.0*g*g*f + cp2*3.0*g*f*f + p2*f*f*f
-                                       pointList.append(point)
-
-                               pointList.append(p2)
-                               p1 = p['p']
-
-               return pointList
-
-       def getSVGPath(self):
-               p0 = self._m(self._startPoint)
-               ret = 'M %f %f ' % (p0.real, p0.imag)
-               for p in self._points:
-                       if p['type'] == Path.LINE:
-                               p0 = self._m(p['p'])
-                               ret += 'L %f %f' % (p0.real, p0.imag)
-                       elif p['type'] == Path.ARC:
-                               p0 = self._m(p['p'])
-                               radius = p['radius']
-                               ret += 'A %f %f 0 %d %d %f %f' % (radius.real, radius.imag, 1 if p['large'] else 0, 1 if p['sweep'] else 0, p0.real, p0.imag)
-                       elif p['type'] == Path.CURVE:
-                               p0 = self._m(p['p'])
-                               cp1 = self._m(p['cp1'])
-                               cp2 = self._m(p['cp2'])
-                               ret += 'C %f %f %f %f %f %f' % (cp1.real, cp1.imag, cp2.real, cp2.imag, p0.real, p0.imag)
-
-               return ret
-
-       def _m(self, p):
-               tmp = numpy.matrix([p.real, p.imag, 1], numpy.float64) * self._matrix
-               return complex(tmp[0,0], tmp[0,1])
-       def _r(self, p):
-               tmp = numpy.matrix([p.real, p.imag], numpy.float64) * self._relMatrix
-               return complex(tmp[0,0], tmp[0,1])
-
 class SVG(object):
        def __init__(self, filename):
                self.tagProcess = {}
@@ -229,6 +98,10 @@ class SVG(object):
                self._xml = None
                f.close()
 
+               for path in self.paths:
+                       if not path.isClosed():
+                               path.checkClosed()
+
        def _processGTag(self, tag, baseMatrix):
                for e in tag:
                        if e.get('transform') is None:
@@ -264,20 +137,20 @@ class SVG(object):
                y1 = toFloat(tag.get('y1', '0'))
                x2 = toFloat(tag.get('x2', '0'))
                y2 = toFloat(tag.get('y2', '0'))
-               p = Path(x1, y1, matrix)
+               p = drawing.Path(x1, y1, matrix)
                p.addLineTo(x2, y2)
                self.paths.append(p)
 
        def _processPolylineTag(self, tag, matrix):
                values = map(toFloat, re.split('[, \t]+', tag.get('points', '').strip()))
-               p = Path(values[0], values[1], matrix)
+               p = drawing.Path(values[0], values[1], matrix)
                for n in xrange(2, len(values)-1, 2):
                        p.addLineTo(values[n], values[n+1])
                self.paths.append(p)
 
        def _processPolygonTag(self, tag, matrix):
                values = map(toFloat, re.split('[, \t]+', tag.get('points', '').strip()))
-               p = Path(values[0], values[1], matrix)
+               p = drawing.Path(values[0], values[1], matrix)
                for n in xrange(2, len(values)-1, 2):
                        p.addLineTo(values[n], values[n+1])
                p.closePath()
@@ -287,7 +160,7 @@ class SVG(object):
                cx = toFloat(tag.get('cx', '0'))
                cy = toFloat(tag.get('cy', '0'))
                r = toFloat(tag.get('r', '0'))
-               p = Path(cx-r, cy, matrix)
+               p = drawing.Path(cx-r, cy, matrix)
                p.addArcTo(cx+r, cy, 0, r, r, False, False)
                p.addArcTo(cx-r, cy, 0, r, r, False, False)
                self.paths.append(p)
@@ -297,7 +170,7 @@ class SVG(object):
                cy = toFloat(tag.get('cy', '0'))
                rx = toFloat(tag.get('rx', '0'))
                ry = toFloat(tag.get('rx', '0'))
-               p = Path(cx-rx, cy, matrix)
+               p = drawing.Path(cx-rx, cy, matrix)
                p.addArcTo(cx+rx, cy, 0, rx, ry, False, False)
                p.addArcTo(cx-rx, cy, 0, rx, ry, False, False)
                self.paths.append(p)
@@ -327,8 +200,7 @@ class SVG(object):
                        ry = 0.0
 
                if rx > 0 and ry > 0:
-                       p = Path(x+rx, y, matrix)
-                       p.addLineTo(x+width-rx, y)
+                       p = drawing.Path(x+width-rx, y, matrix)
                        p.addArcTo(x+width,y+ry, 0, rx, ry, False, True)
                        p.addLineTo(x+width, y+height-ry)
                        p.addArcTo(x+width-rx,y+height, 0, rx, ry, False, True)
@@ -336,9 +208,10 @@ class SVG(object):
                        p.addArcTo(x,y+height-ry, 0, rx, ry, False, True)
                        p.addLineTo(x, y+ry)
                        p.addArcTo(x+rx,y, 0, rx, ry, False, True)
+                       p.closePath()
                        self.paths.append(p)
                else:
-                       p = Path(x, y, matrix)
+                       p = drawing.Path(x, y, matrix)
                        p.addLineTo(x,y+height)
                        p.addLineTo(x+width,y+height)
                        p.addLineTo(x+width,y)
@@ -364,7 +237,7 @@ class SVG(object):
                        if command == 'm':
                                x += params[0]
                                y += params[1]
-                               path = Path(x, y, matrix)
+                               path = drawing.Path(x, y, matrix)
                                self.paths.append(path)
                                params = params[2:]
                                while len(params) > 1:
@@ -376,7 +249,7 @@ class SVG(object):
                        elif command == 'M':
                                x = params[0]
                                y = params[1]
-                               path = Path(x, y, matrix)
+                               path = drawing.Path(x, y, matrix)
                                self.paths.append(path)
                                params = params[2:]
                                while len(params) > 1:
@@ -522,28 +395,4 @@ if __name__ == '__main__':
                print 'File: %s' % (sys.argv[n])
                svg = SVG(sys.argv[n])
 
-       f = open("test_export.html", "w")
-
-       f.write("<!DOCTYPE html><html><body>\n")
-       f.write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style='width:%dpx;height:%dpx'>\n" % (1000, 1000))
-       f.write("<g fill-rule='evenodd' style=\"fill: gray; stroke:black;stroke-width:2\">\n")
-       f.write("<path d=\"")
-       for path in svg.paths:
-               points = path.getPoints()
-               f.write("M %f %f " % (points[0].real, points[0].imag))
-               for point in points[1:]:
-                       f.write("L %f %f " % (point.real, point.imag))
-       f.write("\"/>")
-       f.write("</g>\n")
-
-       f.write("<g style=\"fill: none; stroke:red;stroke-width:1\">\n")
-       f.write("<path d=\"")
-       for path in svg.paths:
-               f.write(path.getSVGPath())
-       f.write("\"/>")
-       f.write("</g>\n")
-
-       f.write("</svg>\n")
-       f.write("</body></html>")
-       f.close()
-
+       drawing.saveAsHtml(svg, "test_export.html")