-
Notifications
You must be signed in to change notification settings - Fork 0
/
svgParser.py
161 lines (127 loc) · 5.3 KB
/
svgParser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import serial
from svgpathtools import svg2paths, wsvg, Line, QuadraticBezier
from xml.dom import minidom
import argparse
import re # for editing the cpp
# Define types for parsing SVG
lineType = type(Line(start=(0+0j),end=(1,1j)))
quadType = type(QuadraticBezier(start=(0+0j), control=(.5+.5j), end=(1+1j)))
# Define parse for CLI
parser = argparse.ArgumentParser(description='Take a file and scale.')
parser.add_argument('filename')
parser.add_argument('minx', type=int)
parser.add_argument('miny', type=int)
parser.add_argument('maxx', type=int)
parser.add_argument('maxy', type=int)
args = parser.parse_args()
# Get the user define output box
outBox = [args.minx,args.miny, args.maxx, args.maxy]
# Use the second solution on this stack overflow post to guarandtee better results
# https://stackoverflow.com/questions/13329125/removing-transforms-in-svg-files
poesvg = open(args.filename, 'r')
doc = minidom.parse(poesvg) # parseString also exists
# Get the svg width and height from an SVG made using the SO toolchain
svgWidth = [el.getAttribute('width') for el
in doc.getElementsByTagName('rect')] or [el.getAttribute('width') for el
in doc.getElementsByTagName('svg')]
svgHeight =[el.getAttribute('height') for el
in doc.getElementsByTagName('rect')] or [el.getAttribute('height') for el
in doc.getElementsByTagName('svg')]
doc.unlink()
print(svgWidth)
print(svgHeight)
# Convert the svg shape into the box format
try:
svgWidth = int(svgWidth[0])
svgHeight = int(svgHeight[0])
except:
print('error reading svgheight and width. Retrying...')
svgWidth = int(''.join(list(filter(str.isdigit, svgWidth[0]))))
svgHeight = int(''.join(list(filter(str.isdigit, svgHeight[0]))))
viewBox=[0,0,svgWidth, svgHeight]
print(svgWidth)
print(svgHeight)
# Initialize marker control variables
currentPosition = (0,0)
markerDown = True
# Initialize string for path
stringToReturn = ""
stringToReturn += "//PYTHONSTARTFLAG \n"
def pointScale(svgBox, outBox, point):
# print(point)
### Scale a point from the size/shape of svg box to the size/shape of outBox
xScale = (outBox[2]-outBox[0])/(svgBox[2]-svgBox[0])
yScale = (outBox[3]-outBox[1])/(svgBox[3]-svgBox[1])
outPoint = (int(point.real *xScale) + outBox[0], int(point.imag*yScale)+outBox[1])
# print(outPoint)
assert outPoint[0] > 150 and outPoint[0] < 1100
assert outPoint[1] > 0 and outPoint[1] < 1200
return outPoint
boundingBox = [10000,10000,0,0]
def testNewBindingBox(pointToTest):
if pointToTest[0] < boundingBox[0]: boundingBox[0] = pointToTest[0]
if pointToTest[0] > boundingBox[2]: boundingBox[2] = pointToTest[0]
if pointToTest[1] < boundingBox[1]: boundingBox[1] = pointToTest[1]
if pointToTest[1] > boundingBox[3]: boundingBox[3] = pointToTest[1]
paths, attributes = svg2paths(args.filename)
stringToReturn += "const int path[][2] = {\n"
numPoints = 0
intNumBytes = 2
arduinoMemSize = 1800
maxPoints = int((arduinoMemSize / intNumBytes))
for path in paths:
if numPoints > maxPoints - 100:
print("WARN: too many points")
break
for seg in path:
if currentPosition != seg.point(0):
numPoints += 1
# If the start point of a segment is off, pen up
stringToReturn += "{-20,0},"
stringToReturn += ('\n')
markerDown = False
if(type(seg)==lineType):
for i in range(0,2):
pointToSend = pointScale(viewBox, outBox, seg.point(i))
testNewBindingBox(pointToSend)
stringToReturn += ("{" + str(pointToSend[0]) + "," + str(pointToSend[1]) + "},")
numPoints += 1
stringToReturn += ('\n')
currentPosition = seg.point(i)
if not(markerDown):
# If the marker is up, set it down
stringToReturn += "{-10,0},"
stringToReturn += ('\n')
markerDown = True
numPoints += 1
if(type(seg)==quadType):
for x in range(0,10):
pointToSend = pointScale(viewBox, outBox, seg.point(x/10.))
testNewBindingBox(pointToSend)
stringToReturn += ("{" + str(pointToSend[0]) + "," + str(pointToSend[1]) + "},")
numPoints += 1
stringToReturn += ('\n')
currentPosition = seg.point(i)
if not(markerDown):
# If the marker is up, set it down
stringToReturn += "{-10,0},"
stringToReturn += ('\n')
markerDown = True
numPoints += 1
stringToReturn += "{-20, 0},\n"
stringToReturn += "{init_pos.x, init_pos.y}\n"
numPoints += 2
stringToReturn += "};\n\n"
stringToReturn += "const int num_path = {};\n".format(numPoints)
stringToReturn +="//PYTHONENDFLAG"
print("num points: {}".format(numPoints))
assert numPoints < maxPoints, "error, svg has too many points too large ({} max)".format(maxPoints)
print(boundingBox)
# Read the current CPP file
with open('src/main.cpp') as f:
cppData = f.read()
# Replace the path with the new path
cppData = re.sub('//PYTHONSTARTFLAG.*?//PYTHONENDFLAG',stringToReturn,cppData,flags=re.DOTALL)
# Write the cpp file again.
cppFile = open('src/main.cpp', 'w')
cppFile.write(cppData)