|
| 1 | +#This file contains just enough logic to get data from the |
| 2 | +#sketchnet svg files as points-on-paths |
| 3 | + |
| 4 | +#info |
| 5 | +#http://www.johndcook.com/blog/2009/12/21/bezier-basics/ |
| 6 | +#https://www.w3.org/TR/SVG/paths.html |
| 7 | + |
| 8 | +#USAGE: |
| 9 | +## If filename is one of the SVG files from sketchnet and you run |
| 10 | +# data = readSketchnet.read(filename) |
| 11 | +##then data2 will be a list of numpy arrays giving strokes |
| 12 | +##of the character. |
| 13 | + |
| 14 | +import xml.etree.ElementTree as ET |
| 15 | +import numpy as np |
| 16 | +import re |
| 17 | + |
| 18 | +ns = {"i":"http://www.w3.org/2000/svg"} |
| 19 | + |
| 20 | +#parses a file to produce a big list of all the path data |
| 21 | +def fileToData(filename): |
| 22 | + num=r"(\d+(\.\d+)?)" |
| 23 | + straight="M{0} {0} L{0} {0} ".format(num) |
| 24 | + curve = "M{0} {0} (C{0} {0} {0} {0} {0} {0} )+".format(num) |
| 25 | + curvepiece = "C{0} {0} {0} {0} {0} {0} ".format(num) |
| 26 | + |
| 27 | + r = ET.parse(filename) |
| 28 | + g = r.find("i:g",ns).find("i:g",ns) |
| 29 | + svgTexts=[p.attrib["d"] for p in g.findall("i:path",ns)] |
| 30 | + |
| 31 | + out = [] |
| 32 | + for text in svgTexts: |
| 33 | + m=re.match(straight, text) |
| 34 | + if m: |
| 35 | + g = m.groups() |
| 36 | + points = ((float(g[0]),float(g[2])),(float(g[4]),float(g[6]))) |
| 37 | + out.append(points) |
| 38 | + else: |
| 39 | + m=re.match(curve, text) |
| 40 | + if(m): |
| 41 | + g = m.groups() |
| 42 | + startpt = (float(g[0]),float(g[2])) |
| 43 | + curvedata = [] |
| 44 | + for p in re.finditer(curvepiece, text): |
| 45 | + g= p.groups() |
| 46 | + vals = ((float(g[0]),float(g[2])), |
| 47 | + (float(g[4]),float(g[6])), |
| 48 | + (float(g[8]),float(g[10]))) |
| 49 | + curvedata.append(vals) |
| 50 | + #print (text,"\n", startpt,curvedata) |
| 51 | + out.append(("C",startpt,curvedata)) #C just for convenience |
| 52 | + else: |
| 53 | + raise RuntimeError("Unexpected path string: "+text) |
| 54 | + return out |
| 55 | + |
| 56 | + |
| 57 | +def prepareCoeffs(): |
| 58 | + t=np.arange(0.1,1,0.1) |
| 59 | + ot = 1-t |
| 60 | + out = np.vstack([ot*ot*ot,3*ot*ot*t,3*ot*t*t,t*t*t]) |
| 61 | + return out.T |
| 62 | +coeffs = prepareCoeffs() #9x4 |
| 63 | + |
| 64 | +#takes the data from a file and returns a list of strokes, |
| 65 | +#each one being an Nx2 numpy array. |
| 66 | +#This means expanding the bezier curves |
| 67 | +def dataToStrokePoints(data): |
| 68 | + out = [] |
| 69 | + for stroke in data: |
| 70 | + if len(stroke)==2: #straight line |
| 71 | + x = np.array(stroke) |
| 72 | + else: |
| 73 | + x=[stroke[1]] |
| 74 | + for i in stroke[2]: |
| 75 | + if False: # show all control points |
| 76 | + for pt in range(3): |
| 77 | + x.append(i[pt]) |
| 78 | + else: |
| 79 | + controlPts=np.vstack([x[-1],i[0],i[1],i[2]]) # 4x2 |
| 80 | + x.append(np.dot(coeffs,controlPts)) #9x2 |
| 81 | + x.append(i[2]) |
| 82 | + out.append(np.vstack(x)) |
| 83 | + return out |
| 84 | + |
| 85 | +def read(filename): |
| 86 | + return dataToStrokePoints(fileToData(filename)) |
0 commit comments