From 169abb6f34854e70e9d3d9048eb379e4cc75188b Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 6 Jan 2012 13:11:19 -0200 Subject: [PATCH] Draft SVG importer now supports quadratic and cubic curves (shoogen) --- src/Mod/Draft/importSVG.py | 124 +++++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 20 deletions(-) diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 0590d7701..ae560f138 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -22,13 +22,12 @@ #*************************************************************************** __title__="FreeCAD Draft Workbench - SVG importer/exporter" -__author__ = "Yorik van Havre " -__url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] +__author__ = "Yorik van Havre, Sebastian Hoogen" +__url__ = ["http://free-cad.sourceforge.net"] ''' This script imports SVG files in FreeCAD. Currently only reads the following entities: paths, lines, arcs and rects. -Bezier curves are skipped. ''' import xml.sax, string, FreeCAD, os, math, re, Draft @@ -373,13 +372,14 @@ class svgHandler(xml.sax.ContentHandler): path = [] point = [] lastvec = Vector(0,0,0) + lastpole = None command = None relative = False firstvec = None pathdata = [] for d in data['d']: - if (len(d) == 1) and (d in ['m','M','l','L','h','H','v','V','a','A','c','C']): + if (len(d) == 1) and (d in ['m','M','l','L','h','H','v','V','a','A','c','C','q','Q','s','S','t','T']): pathdata.append(d) else: try: @@ -453,12 +453,44 @@ class svgHandler(xml.sax.ContentHandler): command = "close" point = [] elif (d == "C"): - command = "curve" + command = "cubic" relative = False + smooth = False point = [] elif (d == "c"): - command = "curve" + command = "cubic" relative = True + smooth = False + point = [] + elif (d == "Q"): + command = "quadratic" + relative = False + smooth = False + point = [] + elif (d == "q"): + command = "quadratic" + relative = True + smooth = False + point = [] + elif (d == "S"): + command = "cubic" + relative = False + smooth = True + point = [] + elif (d == "s"): + command = "cubic" + relative = True + smooth = True + point = [] + elif (d == "T"): + command = "quadratic" + relative = False + smooth = True + point = [] + elif (d == "t"): + command = "quadratic" + relative = True + smooth = True point = [] else: try: @@ -485,6 +517,7 @@ class svgHandler(xml.sax.ContentHandler): firstvec = lastvec print "move ",lastvec command = "line" + lastpole = None point = [] elif (len(point)==2) and (command=="line"): if relative: @@ -496,6 +529,7 @@ class svgHandler(xml.sax.ContentHandler): print "line ",lastvec,currentvec lastvec = currentvec path.append(seg) + lastpole = None point = [] elif (len(point)==1) and (command=="horizontal"): if relative: @@ -505,6 +539,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = Vector(point[0],lasty,0) seg = Part.Line(lastvec,currentvec).toShape() lastvec = currentvec + lastpole = None path.append(seg) point = [] elif (len(point)==1) and (command=="vertical"): @@ -515,6 +550,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = Vector(lastx,-point[0],0) seg = Part.Line(lastvec,currentvec).toShape() lastvec = currentvec + lastpole = None path.append(seg) point = [] elif (len(point)==7) and (command=="arc"): @@ -539,6 +575,7 @@ class svgHandler(xml.sax.ContentHandler): midpoint = lastvec.add(chord.add(perp)) seg = Part.Arc(lastvec,midpoint,currentvec).toShape() lastvec = currentvec + lastpole = None path.append(seg) point = [] elif (command == "close"): @@ -555,31 +592,78 @@ class svgHandler(xml.sax.ContentHandler): path = [] point = [] command = None - elif (len(point)==6) and (command=="curve"): - if relative: - currentvec = lastvec.add(Vector(point[4],-point[5],0)) - pole1 = lastvec.add(Vector(point[0],-point[1],0)) - pole2 = lastvec.add(Vector(point[2],-point[3],0)) - else: - currentvec = Vector(point[4],-point[5],0) - pole1 = Vector(point[0],-point[1],0) - pole2 = Vector(point[2],-point[3],0) + #elif (len(point)==6) and (command=="cubic"): + elif (command=="cubic") and (((smooth==False) and (len(point)==6)) or (smooth==True and (len(point)==4))) : + if smooth: + if relative: + currentvec = lastvec.add(Vector(point[2],-point[3],0)) + pole2 = lastvec.add(Vector(point[0],-point[1],0)) + else: + currentvec = Vector(point[2],-point[3],0) + pole2 = Vector(point[0],-point[1],0) + if lastpole: + pole1 = lastvec.sub(lastpole).add(lastvec) + else: + pole1 = lastvec + else: #not smooth + if relative: + currentvec = lastvec.add(Vector(point[4],-point[5],0)) + pole1 = lastvec.add(Vector(point[0],-point[1],0)) + pole2 = lastvec.add(Vector(point[2],-point[3],0)) + else: + currentvec = Vector(point[4],-point[5],0) + pole1 = Vector(point[0],-point[1],0) + pole2 = Vector(point[2],-point[3],0) + if not fcvec.equals(currentvec,lastvec): mainv = currentvec.sub(lastvec) pole1v = lastvec.add(pole1) pole2v = currentvec.add(pole2) - print "curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize() - if (round(mainv.getAngle(pole1v),Draft.precision()) in [0,round(math.pi,Draft.precision())]) \ - and (round(mainv.getAngle(pole2v),Draft.precision()) in [0,round(math.pi,Draft.precision())]): + print "cubic curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize() + if pole1.distanceToLine(lastvec,currentvec) < 10**(-1*Draft.precision()) and pole2.distanceToLine(lastvec,currentvec) < 10**(-1*Draft.precision()): print "straight segment" seg = Part.Line(lastvec,currentvec).toShape() else: - print "bezier segment" + print "cubic bezier segment" b = Part.BezierCurve() b.setPoles([lastvec,pole1,pole2,currentvec]) seg = b.toShape() print "connect ",lastvec,currentvec lastvec = currentvec + lastpole = pole2 + path.append(seg) + point = [] + + elif (command=="quadratic") and (((smooth==False) and (len(point)==4)) or (smooth==True and (len(point)==2))) : + if smooth: + if relative: + currentvec = lastvec.add(Vector(point[0],-point[1],0)) + else: + currentvec = Vector(point[0],-point[1],0) + if lastpole: + pole1 = lastvec.sub(lastpole).add(lastvec) + else: + pole1 = lastvec + else: #not smooth + if relative: + currentvec = lastvec.add(Vector(point[2],-point[3],0)) + pole1 = lastvec.add(Vector(point[0],-point[1],0)) + else: + currentvec = Vector(point[2],-point[3],0) + pole1 = Vector(point[0],-point[1],0) + + if not fcvec.equals(currentvec,lastvec): + if pole1.distanceToLine(lastvec,currentvec) < 10**(-1*Draft.precision()): + print "straight segment" + seg = Part.Line(lastvec,currentvec).toShape() + else: + print "quadratic bezier segment" + b = Part.BezierCurve() + b.setPoles([lastvec,pole1,currentvec]) + seg = b.toShape() + print "connect ",lastvec,currentvec + lastvec = currentvec + lastpole = pole1 path.append(seg) point = [] @@ -749,7 +833,7 @@ def decodeName(name): try: decodedName = (name.decode("latin1")) except UnicodeDecodeError: - print "dxf: error: couldn't determine character encoding" + print "svg: error: couldn't determine character encoding" decodedName = name return decodedName