Draft importSVG reimplentation of path and transformation parsing
All basic elements besides elliptic arcs and rounded rects are now supported
This commit is contained in:
parent
6d86e84d28
commit
48c9e2fbe8
|
@ -27,9 +27,13 @@ __url__ = ["http://free-cad.sourceforge.net"]
|
||||||
|
|
||||||
'''
|
'''
|
||||||
This script imports SVG files in FreeCAD. Currently only reads the following entities:
|
This script imports SVG files in FreeCAD. Currently only reads the following entities:
|
||||||
paths, lines, arcs ,rects, circles, ellipses, polygons, polylines.
|
paths, lines, circular arcs ,rects, circles, ellipses, polygons, polylines.
|
||||||
currently unsupported: image, rounded rect(rx,ry), transform attribute??
|
currently unsupported: image, rounded rect(rx,ry), elliptical arcs
|
||||||
'''
|
'''
|
||||||
|
#ToDo:
|
||||||
|
# elliptical arc segments
|
||||||
|
# rounded rects (elliptical arcs)
|
||||||
|
# ignoring CDATA
|
||||||
|
|
||||||
import xml.sax, string, FreeCAD, os, math, re, Draft
|
import xml.sax, string, FreeCAD, os, math, re, Draft
|
||||||
from draftlibs import fcvec
|
from draftlibs import fcvec
|
||||||
|
@ -230,43 +234,6 @@ def getrgb(color):
|
||||||
b = str(hex(int(color[2]*255)))[2:].zfill(2)
|
b = str(hex(int(color[2]*255)))[2:].zfill(2)
|
||||||
return "#"+r+g+b
|
return "#"+r+g+b
|
||||||
|
|
||||||
def splitpathd(pathdstr):
|
|
||||||
whitespacechars = [' ','\t','\r','\n']
|
|
||||||
commandchars = ['m','M','l','L','h','H','v','V','a','A','c','C','q','Q','s','S','t','T','z','Z']
|
|
||||||
numberchars = ['e','E','+','-','.','0','1','2','3','4','5','6','7','8','9']
|
|
||||||
dlist=[]
|
|
||||||
currentnumber=''
|
|
||||||
state='whitespace'
|
|
||||||
for dchar in pathdstr:
|
|
||||||
if dchar in commandchars:
|
|
||||||
if currentnumber:
|
|
||||||
dlist.append(float(currentnumber))
|
|
||||||
currentnumber = ''
|
|
||||||
dlist.append(dchar)
|
|
||||||
state='whitespace'
|
|
||||||
elif state == 'whitespace':
|
|
||||||
if dchar in whitespacechars:
|
|
||||||
pass #continue
|
|
||||||
elif dchar in numberchars:
|
|
||||||
state = 'number'
|
|
||||||
currentnumber = dchar
|
|
||||||
else:
|
|
||||||
print 'unexpected char %s %d %s' % (dchar,ord(dchar),state)
|
|
||||||
elif state == 'number':
|
|
||||||
if dchar in numberchars:
|
|
||||||
currentnumber += dchar
|
|
||||||
elif dchar in whitespacechars:
|
|
||||||
dlist.append(float(currentnumber))
|
|
||||||
currentnumber = ''
|
|
||||||
else:
|
|
||||||
print 'unexpected char %s %d %s' % (dchar,ord(dchar),state)
|
|
||||||
#End of string/list
|
|
||||||
if currentnumber:
|
|
||||||
dlist.append(float(currentnumber))
|
|
||||||
currentnumber = ''
|
|
||||||
return dlist
|
|
||||||
|
|
||||||
|
|
||||||
class svgHandler(xml.sax.ContentHandler):
|
class svgHandler(xml.sax.ContentHandler):
|
||||||
"this handler parses the svg files and creates freecad objects"
|
"this handler parses the svg files and creates freecad objects"
|
||||||
|
|
||||||
|
@ -319,6 +286,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
data[keyword]=content
|
data[keyword]=content
|
||||||
|
|
||||||
if 'style' in data:
|
if 'style' in data:
|
||||||
|
if not data['style']:
|
||||||
|
pass#empty style attribute stops inhertig from parent
|
||||||
|
else:
|
||||||
content = data['style'][0].replace(' ','')
|
content = data['style'][0].replace(' ','')
|
||||||
content = content.split(';')
|
content = content.split(';')
|
||||||
for i in content:
|
for i in content:
|
||||||
|
@ -351,7 +321,7 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
if data['stroke-width'] != 'none':
|
if data['stroke-width'] != 'none':
|
||||||
self.width = getsize(data['stroke-width'])
|
self.width = getsize(data['stroke-width'])
|
||||||
if 'transform' in data:
|
if 'transform' in data:
|
||||||
m = self.getMatrix(data['transform'])
|
m = self.getMatrix(attrs.getValue('transform'))
|
||||||
if name == "g":
|
if name == "g":
|
||||||
self.grouptransform.append(m)
|
self.grouptransform.append(m)
|
||||||
else:
|
else:
|
||||||
|
@ -360,37 +330,6 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
if name == "g":
|
if name == "g":
|
||||||
self.grouptransform.append(FreeCAD.Matrix())
|
self.grouptransform.append(FreeCAD.Matrix())
|
||||||
|
|
||||||
'''
|
|
||||||
print "existing grouptransform: ",self.grouptransform
|
|
||||||
print "existing transform: ",self.transform
|
|
||||||
if "translate" in tr:
|
|
||||||
i0 = tr.index("translate")
|
|
||||||
print "getting translate ",tr
|
|
||||||
if "translate" in self.transform:
|
|
||||||
self.transform['translate'] = self.transform['translate'].add(Vector(float(tr[i0+1]),-float(tr[i0+2]),0))
|
|
||||||
else:
|
|
||||||
self.transform['translate'] = Vector(float(tr[i0+1]),-float(tr[i0+2]),0)
|
|
||||||
if "translate" in self.grouptransform:
|
|
||||||
print "adding to group ",self.grouptransform['translate']
|
|
||||||
self.transform['translate'] = self.grouptransform['translate'].add(self.transform['translate'])
|
|
||||||
else:
|
|
||||||
if "translate" in self.grouptransform:
|
|
||||||
print "adding to group ",self.grouptransform['translate']
|
|
||||||
self.transform['translate'] = self.grouptransform['translate']
|
|
||||||
if "scale" in tr:
|
|
||||||
i0 = tr.index("scale")
|
|
||||||
if "scale" in self.transform:
|
|
||||||
self.transform['scale'] = self.transform['scale'].add(Vector(float(tr[i0+1]),float(tr[i0+2]),0))
|
|
||||||
else:
|
|
||||||
print tr
|
|
||||||
self.transform['scale'] = Vector(float(tr[i0+1]),float(tr[i0+2]),0)
|
|
||||||
if "scale" in self.grouptransform:
|
|
||||||
self.transform['scale'] = self.transform['scale'].add(self.grouptransform['scale'])
|
|
||||||
else:
|
|
||||||
if "scale" in self.grouptransform:
|
|
||||||
self.transform['scale'] = self.grouptransform['scale']
|
|
||||||
'''
|
|
||||||
|
|
||||||
if (self.style == 1):
|
if (self.style == 1):
|
||||||
self.color = self.col
|
self.color = self.col
|
||||||
self.width = self.lw
|
self.width = self.lw
|
||||||
|
@ -415,9 +354,6 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
relative = False
|
relative = False
|
||||||
firstvec = None
|
firstvec = None
|
||||||
|
|
||||||
pathdata = splitpathd(' '.join(data['d']))
|
|
||||||
# print "debug: pathdata:",pathdata
|
|
||||||
|
|
||||||
if "freecad:basepoint1" in data:
|
if "freecad:basepoint1" in data:
|
||||||
p1 = data["freecad:basepoint1"]
|
p1 = data["freecad:basepoint1"]
|
||||||
p1 = Vector(float(p1[0]),-float(p1[1]),0)
|
p1 = Vector(float(p1[0]),-float(p1[1]),0)
|
||||||
|
@ -430,8 +366,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
self.format(obj)
|
self.format(obj)
|
||||||
pathdata = []
|
pathdata = []
|
||||||
self.lastdim = obj
|
self.lastdim = obj
|
||||||
|
pathcommandsre=re.compile('\s*?([mMlLhHvVaAcCqQsStTzZ])\s*?([^mMlLhHvVaAcCqQsStTzZ]*)\s*?',re.DOTALL)
|
||||||
for d in pathdata:
|
for d,pointsstr in pathcommandsre.findall(' '.join(data['d'])):
|
||||||
|
#for d in pathdata:
|
||||||
if (d == "M"):
|
if (d == "M"):
|
||||||
command = "move"
|
command = "move"
|
||||||
relative = False
|
relative = False
|
||||||
|
@ -515,12 +452,10 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
relative = True
|
relative = True
|
||||||
smooth = True
|
smooth = True
|
||||||
point = []
|
point = []
|
||||||
else:
|
pointlist = pointsstr.replace(',',' ').split()
|
||||||
try:
|
while pointlist:
|
||||||
point.append(float(d))
|
if pointlist:
|
||||||
except ValueError:
|
point.append(float(pointlist.pop(0)))
|
||||||
pass
|
|
||||||
|
|
||||||
print "command: ",command, ' point: ',point
|
print "command: ",command, ' point: ',point
|
||||||
|
|
||||||
if (len(point)==2) and (command=="move"):
|
if (len(point)==2) and (command=="move"):
|
||||||
|
@ -532,6 +467,8 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
obj.Shape = sh
|
obj.Shape = sh
|
||||||
self.format(obj)
|
self.format(obj)
|
||||||
path = []
|
path = []
|
||||||
|
if firstvec:
|
||||||
|
lastvec = firstvec #Move relative to last move command not last draw command
|
||||||
if relative:
|
if relative:
|
||||||
lastvec = lastvec.add(Vector(point[0],-point[1],0))
|
lastvec = lastvec.add(Vector(point[0],-point[1],0))
|
||||||
command="line"
|
command="line"
|
||||||
|
@ -577,6 +514,8 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
path.append(seg)
|
path.append(seg)
|
||||||
point = []
|
point = []
|
||||||
elif (len(point)==7) and (command=="arc"):
|
elif (len(point)==7) and (command=="arc"):
|
||||||
|
#support for large-arc and x-rotation are missing
|
||||||
|
rx,ry,xrotation, largeflag, sweepflag = point[0:5]
|
||||||
if relative:
|
if relative:
|
||||||
currentvec = lastvec.add(Vector(point[-2],-point[-1],0))
|
currentvec = lastvec.add(Vector(point[-2],-point[-1],0))
|
||||||
else:
|
else:
|
||||||
|
@ -584,16 +523,16 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
chord = currentvec.sub(lastvec)
|
chord = currentvec.sub(lastvec)
|
||||||
# perp = chord.cross(Vector(0,0,-1))
|
# perp = chord.cross(Vector(0,0,-1))
|
||||||
# here is a better way to find the perpendicular
|
# here is a better way to find the perpendicular
|
||||||
if point[4] == 1:
|
if sweepflag == 1:
|
||||||
# clockwise
|
# clockwise
|
||||||
perp = fcvec.rotate2D(chord,-math.pi/2)
|
perp = fcvec.rotate2D(chord,-math.pi/2)
|
||||||
else:
|
else:
|
||||||
# anticlockwise
|
# anticlockwise
|
||||||
perp = fcvec.rotate2D(chord,math.pi/2)
|
perp = fcvec.rotate2D(chord,math.pi/2)
|
||||||
chord = fcvec.scale(chord,.5)
|
chord = fcvec.scale(chord,.5)
|
||||||
if chord.Length > point[0]: a = 0
|
if chord.Length > rx: a = 0
|
||||||
else: a = math.sqrt(point[0]**2-chord.Length**2)
|
else: a = math.sqrt(rx**2-chord.Length**2)
|
||||||
s = point[0] - a
|
s = rx - a
|
||||||
perp = fcvec.scale(perp,s/perp.Length)
|
perp = fcvec.scale(perp,s/perp.Length)
|
||||||
midpoint = lastvec.add(chord.add(perp))
|
midpoint = lastvec.add(chord.add(perp))
|
||||||
seg = Part.Arc(lastvec,midpoint,currentvec).toShape()
|
seg = Part.Arc(lastvec,midpoint,currentvec).toShape()
|
||||||
|
@ -601,21 +540,6 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
lastpole = None
|
lastpole = None
|
||||||
path.append(seg)
|
path.append(seg)
|
||||||
point = []
|
point = []
|
||||||
elif (command == "close"):
|
|
||||||
if not fcvec.equals(lastvec,firstvec):
|
|
||||||
seg = Part.Line(lastvec,firstvec).toShape()
|
|
||||||
path.append(seg)
|
|
||||||
if path:
|
|
||||||
sh = Part.Wire(path)
|
|
||||||
if self.fill: sh = Part.Face(sh)
|
|
||||||
sh = self.applyTrans(sh)
|
|
||||||
obj = self.doc.addObject("Part::Feature",pathname)
|
|
||||||
obj.Shape = sh
|
|
||||||
self.format(obj)
|
|
||||||
path = []
|
|
||||||
point = []
|
|
||||||
command = None
|
|
||||||
|
|
||||||
elif (command=="cubic") and (((smooth==False) and (len(point)==6)) or (smooth==True and (len(point)==4))) :
|
elif (command=="cubic") and (((smooth==False) and (len(point)==6)) or (smooth==True and (len(point)==4))) :
|
||||||
if smooth:
|
if smooth:
|
||||||
if relative:
|
if relative:
|
||||||
|
@ -643,7 +567,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
pole1v = lastvec.add(pole1)
|
pole1v = lastvec.add(pole1)
|
||||||
pole2v = currentvec.add(pole2)
|
pole2v = currentvec.add(pole2)
|
||||||
print "cubic curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize()
|
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()):
|
if True and \
|
||||||
|
pole1.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()) and \
|
||||||
|
pole2.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()):
|
||||||
print "straight segment"
|
print "straight segment"
|
||||||
seg = Part.Line(lastvec,currentvec).toShape()
|
seg = Part.Line(lastvec,currentvec).toShape()
|
||||||
else:
|
else:
|
||||||
|
@ -676,7 +602,7 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
pole1 = Vector(point[0],-point[1],0)
|
pole1 = Vector(point[0],-point[1],0)
|
||||||
|
|
||||||
if not fcvec.equals(currentvec,lastvec):
|
if not fcvec.equals(currentvec,lastvec):
|
||||||
if pole1.distanceToLine(lastvec,currentvec) < 10**(-1*Draft.precision()):
|
if True and pole1.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()):
|
||||||
print "straight segment"
|
print "straight segment"
|
||||||
seg = Part.Line(lastvec,currentvec).toShape()
|
seg = Part.Line(lastvec,currentvec).toShape()
|
||||||
else:
|
else:
|
||||||
|
@ -690,6 +616,29 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
path.append(seg)
|
path.append(seg)
|
||||||
point = []
|
point = []
|
||||||
|
|
||||||
|
#while pointlist or command:
|
||||||
|
else:
|
||||||
|
|
||||||
|
if (command == "close"):
|
||||||
|
if not fcvec.equals(lastvec,firstvec):
|
||||||
|
seg = Part.Line(lastvec,firstvec).toShape()
|
||||||
|
path.append(seg)
|
||||||
|
if path: #the path should be closed by now
|
||||||
|
sh = Part.Wire(path)
|
||||||
|
if not sh.isClosed:
|
||||||
|
#Code from wmayer forum p15549 to fix the tolerance problem
|
||||||
|
comp=Part.Compound(path)
|
||||||
|
sh = comp.connectEdgesToWires(False,10**(-1*Draft.precision())).Wires[0] #original tolerance = 0.00001
|
||||||
|
if self.fill: sh = Part.Face(sh)
|
||||||
|
sh = self.applyTrans(sh)
|
||||||
|
obj = self.doc.addObject("Part::Feature",pathname)
|
||||||
|
obj.Shape = sh
|
||||||
|
self.format(obj)
|
||||||
|
path = []
|
||||||
|
if firstvec:
|
||||||
|
lastvec = firstvec #Move relative to last move command not last draw command
|
||||||
|
point = []
|
||||||
|
command = None
|
||||||
if path:
|
if path:
|
||||||
sh = Part.Wire(path)
|
sh = Part.Wire(path)
|
||||||
if self.fill: sh = Part.Face(sh)
|
if self.fill: sh = Part.Face(sh)
|
||||||
|
@ -698,19 +647,33 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
obj.Shape = sh
|
obj.Shape = sh
|
||||||
self.format(obj)
|
self.format(obj)
|
||||||
|
|
||||||
|
|
||||||
# processing rects
|
# processing rects
|
||||||
|
|
||||||
if name == "rect":
|
if name == "rect":
|
||||||
if not pathname: pathname = 'Rectangle'
|
if not pathname: pathname = 'Rectangle'
|
||||||
|
edges = []
|
||||||
|
# if ('rx' not in data or data['rx'] < 10**(-1*Draft.precision())) and \
|
||||||
|
# ('ry' not in data or data['ry'] < 10**(-1*Draft.precision())): #negative values are invalid
|
||||||
|
if True:
|
||||||
p1 = Vector(data['x'],-data['y'],0)
|
p1 = Vector(data['x'],-data['y'],0)
|
||||||
p2 = Vector(data['x']+data['width'],-data['y'],0)
|
p2 = Vector(data['x']+data['width'],-data['y'],0)
|
||||||
p3 = Vector(data['x']+data['width'],-data['y']-data['height'],0)
|
p3 = Vector(data['x']+data['width'],-data['y']-data['height'],0)
|
||||||
p4 = Vector(data['x'],-data['y']-data['height'],0)
|
p4 = Vector(data['x'],-data['y']-data['height'],0)
|
||||||
edges = []
|
|
||||||
edges.append(Part.Line(p1,p2).toShape())
|
edges.append(Part.Line(p1,p2).toShape())
|
||||||
edges.append(Part.Line(p2,p3).toShape())
|
edges.append(Part.Line(p2,p3).toShape())
|
||||||
edges.append(Part.Line(p3,p4).toShape())
|
edges.append(Part.Line(p3,p4).toShape())
|
||||||
edges.append(Part.Line(p4,p1).toShape())
|
edges.append(Part.Line(p4,p1).toShape())
|
||||||
|
else: #rounded edges
|
||||||
|
rx = data.get('rx')
|
||||||
|
ry = data.get('ry') or rx
|
||||||
|
rx = rx or ry
|
||||||
|
if rx > 2 * data['width']:
|
||||||
|
rx = data['width'] / 2.0
|
||||||
|
if ry > 2 * data['height']:
|
||||||
|
ry = data['height'] / 2.0
|
||||||
|
#TBD
|
||||||
|
# Part.Ellipse(c,rx,ry).toShape() #needs a proxy object
|
||||||
sh = Part.Wire(edges)
|
sh = Part.Wire(edges)
|
||||||
if self.fill: sh = Part.Face(sh)
|
if self.fill: sh = Part.Face(sh)
|
||||||
sh = self.applyTrans(sh)
|
sh = self.applyTrans(sh)
|
||||||
|
@ -722,8 +685,8 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
|
|
||||||
if name == "line":
|
if name == "line":
|
||||||
if not pathname: pathname = 'Line'
|
if not pathname: pathname = 'Line'
|
||||||
p1 = Vector(float(data['x1'][0]),-float(data['y1'][0]),0)
|
p1 = Vector(data['x1'],-data['y1'],0)
|
||||||
p2 = Vector(float(data['x2'][0]),-float(data['y2'][0]),0)
|
p2 = Vector(data['x2'],-data['y2'],0)
|
||||||
sh = Part.Line(p1,p2).toShape()
|
sh = Part.Line(p1,p2).toShape()
|
||||||
sh = self.applyTrans(sh)
|
sh = self.applyTrans(sh)
|
||||||
obj = self.doc.addObject("Part::Feature",pathname)
|
obj = self.doc.addObject("Part::Feature",pathname)
|
||||||
|
@ -733,6 +696,8 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
# processing polylines and polygons
|
# processing polylines and polygons
|
||||||
|
|
||||||
if name == "polyline" or name == "polygon":
|
if name == "polyline" or name == "polygon":
|
||||||
|
'''a simpler implementation would be sh = Part.makePolygon([Vector(svgx,-svgy,0) for svgx,svgy in zip(points[0::2],points[1::2])])
|
||||||
|
but there would be more difficlult to search for duplicate points beforehand.'''
|
||||||
if not pathname: pathname = 'Polyline'
|
if not pathname: pathname = 'Polyline'
|
||||||
points=[float(d) for d in data['points']]
|
points=[float(d) for d in data['points']]
|
||||||
print points
|
print points
|
||||||
|
@ -823,9 +788,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
if self.transform:
|
if self.transform:
|
||||||
vec = self.translateVec(vec,self.transform)
|
vec = self.translateVec(vec,self.transform)
|
||||||
print "own transform: ",self.transform, vec
|
print "own transform: ",self.transform, vec
|
||||||
for i in range(len(self.grouptransform)):
|
for transform in self.grouptransform[::-1]:
|
||||||
#vec = self.translateVec(vec,self.grouptransform[-i-1])
|
#vec = self.translateVec(vec,transform)
|
||||||
vec = self.grouptransform[-i-1].multiply(vec)
|
vec = transform.multiply(vec)
|
||||||
print "applying vector: ",vec
|
print "applying vector: ",vec
|
||||||
obj.Position = vec
|
obj.Position = vec
|
||||||
if gui:
|
if gui:
|
||||||
|
@ -846,9 +811,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
if self.transform:
|
if self.transform:
|
||||||
print "applying object transform: ",self.transform
|
print "applying object transform: ",self.transform
|
||||||
sh = sh.transformGeometry(self.transform)
|
sh = sh.transformGeometry(self.transform)
|
||||||
for i in range(len(self.grouptransform)):
|
for transform in self.grouptransform[::-1]:
|
||||||
print "applying group transform: ",self.grouptransform[-i-1]
|
print "applying group transform: ", transform
|
||||||
sh = sh.transformGeometry(self.grouptransform[-i-1])
|
sh = sh.transformGeometry(transform)
|
||||||
return sh
|
return sh
|
||||||
elif Draft.getType(sh) == "Dimension":
|
elif Draft.getType(sh) == "Dimension":
|
||||||
pts = []
|
pts = []
|
||||||
|
@ -857,9 +822,9 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
if self.transform:
|
if self.transform:
|
||||||
print "applying object transform: ",self.transform
|
print "applying object transform: ",self.transform
|
||||||
cp = self.transform.multiply(cp)
|
cp = self.transform.multiply(cp)
|
||||||
for i in range(len(self.grouptransform)):
|
for transform in self.grouptransform[::-1]:
|
||||||
print "applying group transform: ",self.grouptransform[-i-1]
|
print "applying group transform: ",transform
|
||||||
cp = self.grouptransform[-i-1].multiply(cp)
|
cp = transform.multiply(cp)
|
||||||
pts.append(cp)
|
pts.append(cp)
|
||||||
sh.Start = pts[0]
|
sh.Start = pts[0]
|
||||||
sh.End = pts[1]
|
sh.End = pts[1]
|
||||||
|
@ -871,24 +836,44 @@ class svgHandler(xml.sax.ContentHandler):
|
||||||
|
|
||||||
def getMatrix(self,tr):
|
def getMatrix(self,tr):
|
||||||
"returns a FreeCAD matrix from a svg transform attribute"
|
"returns a FreeCAD matrix from a svg transform attribute"
|
||||||
s = ""
|
transformre=re.compile('(matrix|translate|scale|rotate|skewX|skewY)\s*?\((.*?)\)',re.DOTALL)
|
||||||
for l in tr:
|
|
||||||
s += l
|
|
||||||
s += " "
|
|
||||||
s=s.replace("("," ")
|
|
||||||
s=s.replace(")"," ")
|
|
||||||
s = s.strip()
|
|
||||||
tr = s.split()
|
|
||||||
m = FreeCAD.Matrix()
|
m = FreeCAD.Matrix()
|
||||||
for i in range(len(tr)):
|
for transformation, arguments in transformre.findall(tr):
|
||||||
if tr[i] == 'translate':
|
argsplit=[float(arg) for arg in arguments.replace(',',' ').split()]
|
||||||
vec = Vector(float(tr[i+1]),-float(tr[i+2]),0)
|
#m.multiply(FreeCAD.Matrix (1,0,0,0,0,-1))
|
||||||
m.move(vec)
|
print '%s:%s %s %d' % (transformation, arguments,argsplit,len(argsplit))
|
||||||
elif tr[i] == 'scale':
|
if transformation == 'translate':
|
||||||
vec = Vector(float(tr[i+1]),float(tr[i+2]),0)
|
tx = argsplit[0]
|
||||||
m.scale(vec)
|
ty = argsplit[1] if len(argsplit) > 1 else 0.0
|
||||||
#elif tr[i] == 'rotate':
|
m.move(Vector(tx,-ty,0))
|
||||||
# m.rotateZ(float(tr[i+1]))
|
elif transformation == 'scale':
|
||||||
|
sx = argsplit[0]
|
||||||
|
sy = argsplit[1] if len(argsplit) > 1 else sx
|
||||||
|
m.scale(Vector(sx,sy,1))
|
||||||
|
elif transformation == 'rotate':
|
||||||
|
angle = argsplit[0]
|
||||||
|
if len(argsplit) >= 3:
|
||||||
|
cx = argsplit[1]
|
||||||
|
cy = argsplit[2]
|
||||||
|
m.move(Vector(cx,-cy,0))
|
||||||
|
m.rotateZ(math.radians(-angle)) #mirroring one axis equals changing the direction of rotaion
|
||||||
|
if len(argsplit) >= 3:
|
||||||
|
m.move(Vector(-cx,cy,0))
|
||||||
|
elif transformation == 'skewX':
|
||||||
|
m=m.multiply(FreeCAD.Matrix(1,-math.tan(math.radians(argsplit[0]))))
|
||||||
|
elif transformation == 'skewY':
|
||||||
|
m=m.multiply(FreeCAD.Matrix(1,0,0,0,-math.tan(math.radians(argsplit[0]))))
|
||||||
|
elif transformation == 'matrix':
|
||||||
|
# '''transformation matrix:
|
||||||
|
# FreeCAD SVG
|
||||||
|
# (+A -C +0 +E) (A C 0 E)
|
||||||
|
# (-B +D -0 -F) = (-Y) * (B D 0 F) *(-Y)
|
||||||
|
# (+0 -0 +1 +0) (0 0 1 0)
|
||||||
|
# (+0 -0 +0 +1) (0 0 0 1)'''
|
||||||
|
m=m.multiply(FreeCAD.Matrix(argsplit[0],-argsplit[2],0,argsplit[4],-argsplit[1],argsplit[3],0,-argsplit[5]))
|
||||||
|
else:
|
||||||
|
print 'SKIPPED %s' % transformation
|
||||||
|
print "m= ",m
|
||||||
print "generating transformation: ",m
|
print "generating transformation: ",m
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user