On this page:
4.1 The path-command format
parse-svg-path
svg-path->dc-paths
path-data->dc-paths
elliptical-arc-dc-path

4 Path Data🔗ℹ

These functions parse the d attribute’s path-data mini-language (the same grammar used by <path>, and by SVG2’s d CSS property) and turn it into dc-path% objects ready to hand to a dc<%>. They cover the full grammar — all six drawing commands and their relative/absolute/repeated forms, elliptical arcs, and the shorthand "smooth" curve variants — and were verified against librsvg pixel-for-pixel across each command, not just checked for successful parsing.

The parsing is split into two stages, each independently useful:

  • parse-svg-path turns a d string into a list of path commands a small, inspectable, symbolic representation (e.g. '((M (10 20)) (L (30 40)) (Z))) — without touching racket/draw at all. Use this if you want to inspect, transform, or generate path data programmatically.

  • svg-path->dc-paths turns that command list into actual dc-path% objects. Use this once you have commands (whether from parse-svg-path or built by hand) and want something to actually draw.

path-data->dc-paths is the two stages composed, for the common case of going straight from a d string to dc-path%s. All three feed the same downstream geometry, shown here once as a filled triangle:

a filled, stroked triangle drawn from path data "M0,0 L50,0 L25,50 Z"

4.1 The path-command format🔗ℹ

parse-svg-path represents each path-data command as a list whose first element is a symbol naming the command (matching the SVG letter exactly, including case — 'M for absolute moveto, 'm for relative) and whose remaining elements are its arguments:

Command(s)

  

Shape

  

Example

M, m

  

one coordinate pair

  

(M (10 20))

L, l

  

one or more coordinate pairs

  

(L (10 20) (30 40))

H, h

  

one or more bare numbers (x only)

  

(H 10 30)

V, v

  

one or more bare numbers (y only)

  

(V 10 30)

C, c

  

one or more (x1 y1) (x2 y2) (x y) triplets

  

(C (1 2) (3 4) (5 6))

S, s

  

one or more (x2 y2) (x y) pairs

  

(S (3 4) (5 6))

Q, q

  

one or more (qx qy) (x y) pairs

  

(Q (3 4) (5 6))

T, t

  

one or more coordinate pairs

  

(T (5 6))

A, a

  

one or more (rx ry rot large-arc sweep x y)

  

(A (10 10 0 0 1 20 20))

Z, z

  

no arguments

  

(Z)

A repeated command (e.g. "L 10 20 30 40") produces one list entry with all of its repetitions as separate arguments, not one entry per repetition — '(L (10 20) (30 40)), not '((L (10 20)) (L (30 40))).

A syntax error partway through a d string does not raise — following SVG2’s own error-handling model, parse-svg-path returns everything successfully parsed before the error, discarding only what came at or after it (this also means a single malformed path can’t take down the rendering of an entire document; see svg-path->dc-paths for what happens to a partially-parsed command list).

Examples:
> (parse-svg-path "M 10 20 L 30 40 Z")

'((M (10 20)) (L (30 40)) (Z))

> (parse-svg-path "M 0 0 L 3 -4 Z # not valid path syntax")

'((M (0 0)) (L (3 -4)) (Z))

procedure

(parse-svg-path x)  (listof list?)

  x : (or/c string? input-port?)
Parses x (path data, as a string or an input port) into a list of path commands, in the format described above. Accepts both the full grammar (M/L/H/V/C/S/Q/T/A/Z, upper- and lowercase, repeated forms, comma-or-whitespace-separated arguments) and empty/whitespace-only input (which produces '()).

Example:
> (parse-svg-path "M0,0 H100 V100 H0 Z")

'((M (0 0)) (H 100) (V 100) (H 0) (Z))

procedure

(svg-path->dc-paths commands)  (listof (is-a?/c dc-path%))

  commands : (listof list?)
Converts a list of path commands (in the format parse-svg-path produces) into one or more dc-path% objects, ready to draw or measure via racket/draw. Produces more than one dc-path% when the path data has more than one subpath (i.e., more than one M/m command) — draw or fill each one separately, or collect them with combined-bounding-box if you need their combined extent.

(define paths (svg-path->dc-paths (parse-svg-path "M0,0 L50,0 L25,50 Z")))
(send dc draw-path (first paths) 0 0)

procedure

(path-data->dc-paths d)  (listof (is-a?/c dc-path%))

  d : string?
Equivalent to (svg-path->dc-paths (parse-svg-path d)) parses path data straight to dc-path% objects, for when you don’t need the intermediate command list.

(path-data->dc-paths "M0,0 L50,0 L25,50 Z")

procedure

(elliptical-arc-dc-path x1 
  y1 
  x2 
  y2 
  rx 
  ry 
  x-axis-rotation-deg 
  large-arc-flag 
  sweep-flag) 
  (is-a?/c dc-path%)
  x1 : real?
  y1 : real?
  x2 : real?
  y2 : real?
  rx : real?
  ry : real?
  x-axis-rotation-deg : real?
  large-arc-flag : (or/c 0 1)
  sweep-flag : (or/c 0 1)
Builds a single dc-path% for one elliptical arc segment, from the SVG path-data A/a command’s own parameterization: start point (x1 ,y1), end point (x2 ,y2), the ellipse’s radii rx/ry, its rotation in degrees, and the two flags that disambiguate which of the (up to four) ellipses meeting those constraints to use. This is the endpoint-to-center conversion the SVG spec itself specifies, implemented directly (not approximated) — used internally by svg-path->dc-paths for every A/a command, and exported in case you want an arc segment without going through path-data parsing at all.

Degenerate inputs (rx or ry of 0, or an identical start and end point) are the caller’s responsibility to handle — svg-path->dc-paths checks for both and substitutes a straight line, per spec, before ever calling this function; calling it directly with a zero radius does not raise, but also does not produce a meaningful arc.

(elliptical-arc-dc-path 0 0 50 50 50 50 0 0 1)

an elliptical arc curving upward between two black endpoint dots