Public Member Functions | |
def | __init__ |
def | __repr__ |
def | parse |
def | parse_boolean |
def | parse_command |
def | parse_number |
def | parse_whitespace |
def | SVG |
Public Attributes | |
attr | |
d | |
Static Public Attributes | |
dictionary | defaults = {} |
Path represents an SVG path, an arbitrary set of curves and straight segments. Unlike SVG("path", d="..."), Path stores coordinates as a list of numbers, rather than a string, so that it is transformable in a Fig. Path(d, attribute=value) d required path data attribute=value pairs keyword list SVG attributes See https://www.w3.org/TR/SVG/paths.html for specification of paths from text. Internally, Path data is a list of tuples with these definitions: * ("Z/z",): close the current path * ("H/h", x) or ("V/v", y): a horizontal or vertical line segment to x or y * ("M/m/L/l/T/t", x, y, global): moveto, lineto, or smooth quadratic curveto point (x, y). If global=True, (x, y) should not be transformed. * ("S/sQ/q", cx, cy, cglobal, x, y, global): polybezier or smooth quadratic curveto point (x, y) using (cx, cy) as a control point. If cglobal or global=True, (cx, cy) or (x, y) should not be transformed. * ("C/c", c1x, c1y, c1global, c2x, c2y, c2global, x, y, global): cubic curveto point (x, y) using (c1x, c1y) and (c2x, c2y) as control points. If c1global, c2global, or global=True, (c1x, c1y), (c2x, c2y), or (x, y) should not be transformed. * ("A/a", rx, ry, rglobal, x-axis-rotation, angle, large-arc-flag, sweep-flag, x, y, global): arcto point (x, y) using the aforementioned parameters. * (",/.", rx, ry, rglobal, angle, x, y, global): an ellipse at point (x, y) with radii (rx, ry). If angle is 0, the whole ellipse is drawn; otherwise, a partial ellipse is drawn.
def svgfig::Path::__init__ | ( | self, | |
d = [] , |
|||
attr | |||
) |
def svgfig::Path::__repr__ | ( | self | ) |
def svgfig::Path::parse | ( | self, | |
pathdata | |||
) |
Parses text-commands, converting them into a list of tuples. Called by the constructor.
Definition at line 1117 of file svgfig.py.
01118 : 01119 """Parses text-commands, converting them into a list of tuples. 01120 Called by the constructor.""" 01121 output = [] 01122 index = 0 01123 while True: 01124 command, index, pathdata = self.parse_command(index, pathdata) 01125 index, pathdata = self.parse_whitespace(index, pathdata) 01126 01127 if command == None and index == len(pathdata): break # this is the normal way out of the loop 01128 if command in ("Z", "z"): 01129 output.append((command,)) 01130 01131 ###################### 01132 elif command in ("H", "h", "V", "v"): 01133 errstring = "Path command \"%s\" requires a number at index %d" % (command, index) 01134 num1, index, pathdata = self.parse_number(index, pathdata) 01135 if num1 == None: raise ValueError, errstring 01136 01137 while num1 != None: 01138 output.append((command, num1)) 01139 num1, index, pathdata = self.parse_number(index, pathdata) 01140 01141 ###################### 01142 elif command in ("M", "m", "L", "l", "T", "t"): 01143 errstring = "Path command \"%s\" requires an x,y pair at index %d" % (command, index) 01144 num1, index, pathdata = self.parse_number(index, pathdata) 01145 num2, index, pathdata = self.parse_number(index, pathdata) 01146 01147 if num1 == None: raise ValueError, errstring 01148 01149 while num1 != None: 01150 if num2 == None: raise ValueError, errstring 01151 output.append((command, num1, num2, False)) 01152 01153 num1, index, pathdata = self.parse_number(index, pathdata) 01154 num2, index, pathdata = self.parse_number(index, pathdata) 01155 01156 ###################### 01157 elif command in ("S", "s", "Q", "q"): 01158 errstring = "Path command \"%s\" requires a cx,cy,x,y quadruplet at index %d" % (command, index) 01159 num1, index, pathdata = self.parse_number(index, pathdata) 01160 num2, index, pathdata = self.parse_number(index, pathdata) 01161 num3, index, pathdata = self.parse_number(index, pathdata) 01162 num4, index, pathdata = self.parse_number(index, pathdata) 01163 01164 if num1 == None: raise ValueError, errstring 01165 01166 while num1 != None: 01167 if num2 == None or num3 == None or num4 == None: raise ValueError, errstring 01168 output.append((command, num1, num2, False, num3, num4, False)) 01169 01170 num1, index, pathdata = self.parse_number(index, pathdata) 01171 num2, index, pathdata = self.parse_number(index, pathdata) 01172 num3, index, pathdata = self.parse_number(index, pathdata) 01173 num4, index, pathdata = self.parse_number(index, pathdata) 01174 01175 ###################### 01176 elif command in ("C", "c"): 01177 errstring = "Path command \"%s\" requires a c1x,c1y,c2x,c2y,x,y sextuplet at index %d" % (command, index) 01178 num1, index, pathdata = self.parse_number(index, pathdata) 01179 num2, index, pathdata = self.parse_number(index, pathdata) 01180 num3, index, pathdata = self.parse_number(index, pathdata) 01181 num4, index, pathdata = self.parse_number(index, pathdata) 01182 num5, index, pathdata = self.parse_number(index, pathdata) 01183 num6, index, pathdata = self.parse_number(index, pathdata) 01184 01185 if num1 == None: raise ValueError, errstring 01186 01187 while num1 != None: 01188 if num2 == None or num3 == None or num4 == None or num5 == None or num6 == None: raise ValueError, errstring 01189 01190 output.append((command, num1, num2, False, num3, num4, False, num5, num6, False)) 01191 01192 num1, index, pathdata = self.parse_number(index, pathdata) 01193 num2, index, pathdata = self.parse_number(index, pathdata) 01194 num3, index, pathdata = self.parse_number(index, pathdata) 01195 num4, index, pathdata = self.parse_number(index, pathdata) 01196 num5, index, pathdata = self.parse_number(index, pathdata) 01197 num6, index, pathdata = self.parse_number(index, pathdata) 01198 01199 ###################### 01200 elif command in ("A", "a"): 01201 errstring = "Path command \"%s\" requires a rx,ry,angle,large-arc-flag,sweep-flag,x,y septuplet at index %d" % (command, index) 01202 num1, index, pathdata = self.parse_number(index, pathdata) 01203 num2, index, pathdata = self.parse_number(index, pathdata) 01204 num3, index, pathdata = self.parse_number(index, pathdata) 01205 num4, index, pathdata = self.parse_boolean(index, pathdata) 01206 num5, index, pathdata = self.parse_boolean(index, pathdata) 01207 num6, index, pathdata = self.parse_number(index, pathdata) 01208 num7, index, pathdata = self.parse_number(index, pathdata) 01209 01210 if num1 == None: raise ValueError, errstring 01211 01212 while num1 != None: 01213 if num2 == None or num3 == None or num4 == None or num5 == None or num6 == None or num7 == None: raise ValueError, errstring 01214 01215 output.append((command, num1, num2, False, num3, num4, num5, num6, num7, False)) 01216 01217 num1, index, pathdata = self.parse_number(index, pathdata) 01218 num2, index, pathdata = self.parse_number(index, pathdata) 01219 num3, index, pathdata = self.parse_number(index, pathdata) 01220 num4, index, pathdata = self.parse_boolean(index, pathdata) 01221 num5, index, pathdata = self.parse_boolean(index, pathdata) 01222 num6, index, pathdata = self.parse_number(index, pathdata) 01223 num7, index, pathdata = self.parse_number(index, pathdata) 01224 01225 return output
def svgfig::Path::parse_boolean | ( | self, | |
index, | |||
pathdata | |||
) |
Part of Path's text-command parsing algorithm; used internally.
Definition at line 1104 of file svgfig.py.
01105 : 01106 """Part of Path's text-command parsing algorithm; used internally.""" 01107 index, pathdata = self.parse_whitespace(index, pathdata) 01108 01109 if index >= len(pathdata): return None, index, pathdata 01110 first_digit = pathdata[index] 01111 01112 if first_digit in ("0", "1"): 01113 index += 1 01114 return int(first_digit), index, pathdata 01115 else: 01116 return None, index, pathdata
def svgfig::Path::parse_command | ( | self, | |
index, | |||
pathdata | |||
) |
Part of Path's text-command parsing algorithm; used internally.
Definition at line 1074 of file svgfig.py.
01075 : 01076 """Part of Path's text-command parsing algorithm; used internally.""" 01077 index, pathdata = self.parse_whitespace(index, pathdata) 01078 01079 if index >= len(pathdata): return None, index, pathdata 01080 command = pathdata[index] 01081 if "A" <= command <= "Z" or "a" <= command <= "z": 01082 index += 1 01083 return command, index, pathdata 01084 else: 01085 return None, index, pathdata
def svgfig::Path::parse_number | ( | self, | |
index, | |||
pathdata | |||
) |
Part of Path's text-command parsing algorithm; used internally.
Definition at line 1086 of file svgfig.py.
01087 : 01088 """Part of Path's text-command parsing algorithm; used internally.""" 01089 index, pathdata = self.parse_whitespace(index, pathdata) 01090 01091 if index >= len(pathdata): return None, index, pathdata 01092 first_digit = pathdata[index] 01093 01094 if "0" <= first_digit <= "9" or first_digit in ("-", "+", "."): 01095 start = index 01096 while index < len(pathdata) and ("0" <= pathdata[index] <= "9" or pathdata[index] in ("-", "+", ".", "e", "E")): 01097 index += 1 01098 end = index 01099 01100 index = end 01101 return float(pathdata[start:end]), index, pathdata 01102 else: 01103 return None, index, pathdata
def svgfig::Path::parse_whitespace | ( | self, | |
index, | |||
pathdata | |||
) |
Part of Path's text-command parsing algorithm; used internally.
def svgfig::Path::SVG | ( | self, | |
trans = None |
|||
) |
Apply the transformation "trans" and return an SVG object.
Definition at line 1226 of file svgfig.py.
01227 : 01228 """Apply the transformation "trans" and return an SVG object.""" 01229 if isinstance(trans, basestring): trans = totrans(trans) 01230 01231 x, y, X, Y = None, None, None, None 01232 output = [] 01233 for datum in self.d: 01234 if not isinstance(datum, (tuple, list)): 01235 raise TypeError, "pathdata elements must be tuples/lists" 01236 01237 command = datum[0] 01238 01239 ###################### 01240 if command in ("Z", "z"): 01241 x, y, X, Y = None, None, None, None 01242 output.append("Z") 01243 01244 ###################### 01245 elif command in ("H", "h", "V", "v"): 01246 command, num1 = datum 01247 01248 if command == "H" or (command == "h" and x == None): x = num1 01249 elif command == "h": x += num1 01250 elif command == "V" or (command == "v" and y == None): y = num1 01251 elif command == "v": y += num1 01252 01253 if trans == None: X, Y = x, y 01254 else: X, Y = trans(x, y) 01255 01256 output.append("L%g %g" % (X, Y)) 01257 01258 ###################### 01259 elif command in ("M", "m", "L", "l", "T", "t"): 01260 command, num1, num2, isglobal12 = datum 01261 01262 if trans == None or isglobal12: 01263 if command.isupper() or X == None or Y == None: 01264 X, Y = num1, num2 01265 else: 01266 X += num1 01267 Y += num2 01268 x, y = X, Y 01269 01270 else: 01271 if command.isupper() or x == None or y == None: 01272 x, y = num1, num2 01273 else: 01274 x += num1 01275 y += num2 01276 X, Y = trans(x, y) 01277 01278 COMMAND = command.capitalize() 01279 output.append("%s%g %g" % (COMMAND, X, Y)) 01280 01281 ###################### 01282 elif command in ("S", "s", "Q", "q"): 01283 command, num1, num2, isglobal12, num3, num4, isglobal34 = datum 01284 01285 if trans == None or isglobal12: 01286 if command.isupper() or X == None or Y == None: 01287 CX, CY = num1, num2 01288 else: 01289 CX = X + num1 01290 CY = Y + num2 01291 01292 else: 01293 if command.isupper() or x == None or y == None: 01294 cx, cy = num1, num2 01295 else: 01296 cx = x + num1 01297 cy = y + num2 01298 CX, CY = trans(cx, cy) 01299 01300 if trans == None or isglobal34: 01301 if command.isupper() or X == None or Y == None: 01302 X, Y = num3, num4 01303 else: 01304 X += num3 01305 Y += num4 01306 x, y = X, Y 01307 01308 else: 01309 if command.isupper() or x == None or y == None: 01310 x, y = num3, num4 01311 else: 01312 x += num3 01313 y += num4 01314 X, Y = trans(x, y) 01315 01316 COMMAND = command.capitalize() 01317 output.append("%s%g %g %g %g" % (COMMAND, CX, CY, X, Y)) 01318 01319 ###################### 01320 elif command in ("C", "c"): 01321 command, num1, num2, isglobal12, num3, num4, isglobal34, num5, num6, isglobal56 = datum 01322 01323 if trans == None or isglobal12: 01324 if command.isupper() or X == None or Y == None: 01325 C1X, C1Y = num1, num2 01326 else: 01327 C1X = X + num1 01328 C1Y = Y + num2 01329 01330 else: 01331 if command.isupper() or x == None or y == None: 01332 c1x, c1y = num1, num2 01333 else: 01334 c1x = x + num1 01335 c1y = y + num2 01336 C1X, C1Y = trans(c1x, c1y) 01337 01338 if trans == None or isglobal34: 01339 if command.isupper() or X == None or Y == None: 01340 C2X, C2Y = num3, num4 01341 else: 01342 C2X = X + num3 01343 C2Y = Y + num4 01344 01345 else: 01346 if command.isupper() or x == None or y == None: 01347 c2x, c2y = num3, num4 01348 else: 01349 c2x = x + num3 01350 c2y = y + num4 01351 C2X, C2Y = trans(c2x, c2y) 01352 01353 if trans == None or isglobal56: 01354 if command.isupper() or X == None or Y == None: 01355 X, Y = num5, num6 01356 else: 01357 X += num5 01358 Y += num6 01359 x, y = X, Y 01360 01361 else: 01362 if command.isupper() or x == None or y == None: 01363 x, y = num5, num6 01364 else: 01365 x += num5 01366 y += num6 01367 X, Y = trans(x, y) 01368 01369 COMMAND = command.capitalize() 01370 output.append("%s%g %g %g %g %g %g" % (COMMAND, C1X, C1Y, C2X, C2Y, X, Y)) 01371 01372 ###################### 01373 elif command in ("A", "a"): 01374 command, num1, num2, isglobal12, angle, large_arc_flag, sweep_flag, num3, num4, isglobal34 = datum 01375 01376 oldx, oldy = x, y 01377 OLDX, OLDY = X, Y 01378 01379 if trans == None or isglobal34: 01380 if command.isupper() or X == None or Y == None: 01381 X, Y = num3, num4 01382 else: 01383 X += num3 01384 Y += num4 01385 x, y = X, Y 01386 01387 else: 01388 if command.isupper() or x == None or y == None: 01389 x, y = num3, num4 01390 else: 01391 x += num3 01392 y += num4 01393 X, Y = trans(x, y) 01394 01395 if x != None and y != None: 01396 centerx, centery = (x + oldx)/2., (y + oldy)/2. 01397 CENTERX, CENTERY = (X + OLDX)/2., (Y + OLDY)/2. 01398 01399 if trans == None or isglobal12: 01400 RX = CENTERX + num1 01401 RY = CENTERY + num2 01402 01403 else: 01404 rx = centerx + num1 01405 ry = centery + num2 01406 RX, RY = trans(rx, ry) 01407 01408 COMMAND = command.capitalize() 01409 output.append("%s%g %g %g %d %d %g %g" % (COMMAND, RX - CENTERX, RY - CENTERY, angle, large_arc_flag, sweep_flag, X, Y)) 01410 01411 elif command in (",", "."): 01412 command, num1, num2, isglobal12, angle, num3, num4, isglobal34 = datum 01413 if trans == None or isglobal34: 01414 if command == "." or X == None or Y == None: 01415 X, Y = num3, num4 01416 else: 01417 X += num3 01418 Y += num4 01419 x, y = None, None 01420 01421 else: 01422 if command == "." or x == None or y == None: 01423 x, y = num3, num4 01424 else: 01425 x += num3 01426 y += num4 01427 X, Y = trans(x, y) 01428 01429 if trans == None or isglobal12: 01430 RX = X + num1 01431 RY = Y + num2 01432 01433 else: 01434 rx = x + num1 01435 ry = y + num2 01436 RX, RY = trans(rx, ry) 01437 01438 RX, RY = RX - X, RY - Y 01439 01440 X1, Y1 = X + RX * math.cos(angle*math.pi/180.), Y + RX * math.sin(angle*math.pi/180.) 01441 X2, Y2 = X + RY * math.sin(angle*math.pi/180.), Y - RY * math.cos(angle*math.pi/180.) 01442 X3, Y3 = X - RX * math.cos(angle*math.pi/180.), Y - RX * math.sin(angle*math.pi/180.) 01443 X4, Y4 = X - RY * math.sin(angle*math.pi/180.), Y + RY * math.cos(angle*math.pi/180.) 01444 01445 output.append("M%g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %g" \ 01446 % (X1, Y1, RX, RY, angle, X2, Y2, RX, RY, angle, X3, Y3, RX, RY, angle, X4, Y4, RX, RY, angle, X1, Y1)) 01447 01448 return SVG("path", d="".join(output), **self.attr)
dictionary svgfig::Path::defaults = {} [static] |