Drawing Bezier Curves

This blog post shows to use the racket/draw library to draw Bezier curves.

A Bezier curve connects two points, so we need a way to represent points.

(struct pt (x y))

A Bezier curve from p0 to p3 with control points p1 and p2 is represented by a bez structure:

(struct bez (p0 p1 p2 p3))

The curve leaves p0 in the direction towards p1 . The curve approaches p3 in the direction from p2 .

Given these structure definitions we can now represent Picasso’s Dachshund (see Jeremy Kun’s Blog).

( define dachshund ( list ( bez ( pt 180 280 ) ( pt 183 263 ) ( pt 186 256 ) ( pt 189 244 ) ) ( bez ( pt 191 244 ) ( pt 290 244 ) ( pt 300 230 ) ( pt 339 245 ) ) ( bez ( pt 340 246 ) ( pt 350 290 ) ( pt 360 300 ) ( pt 355 210 ) ) ( bez ( pt 353 210 ) ( pt 370 207 ) ( pt 380 196 ) ( pt 375 193 ) ) ( bez ( pt 375 193 ) ( pt 310 220 ) ( pt 190 220 ) ( pt 164 205 ) ) ( bez ( pt 164 205 ) ( pt 135 194 ) ( pt 135 265 ) ( pt 153 275 ) ) ( bez ( pt 153 275 ) ( pt 168 275 ) ( pt 170 180 ) ( pt 150 190 ) ) ( bez ( pt 149 190 ) ( pt 122 214 ) ( pt 142 204 ) ( pt 85 240 ) ) ( bez ( pt 86 240 ) ( pt 100 247 ) ( pt 125 233 ) ( pt 140 238 ) ) ) )

The racket/draw library represents Bezier curves (or rather zero or more closed subpaths and one open subpath) as dc-path% objects. The function bez->dc-path converts the representation of a Bezier curve from a bez structure into dc-path%.

( define ( bez->dc-path b ) ( match-define ( bez ( pt x0 y0 ) ( pt x1 y1 ) ( pt x2 y2 ) ( pt x3 y3 ) ) b ) ( define p ( new dc-path% ) ) ( send p move-to x0 y0 ) ( send p curve-to x1 y1 x2 y2 x3 y3 ) p )

It is now trivial to define a function, that draws a Bezier curve using a given drawing context, dc:

( define ( draw-bez dc b ) ( send dc draw-path ( bez->dc-path b ) ) )

The dachshund is drawn piece by piece:

( define ( draw-dachshund dc ) ( for ( [ b dachshund ] ) ( draw-bez dc b ) ) )

Using drawing contexts allow to use the same draw-dachshund function to draw the dachshund on pdfs, bitmaps, and, more. Let’s draw the dachshund on a bitmap.

( define bm ( make-object bitmap% 400 100 ) ) ( define dc ( new bitmap-dc% [ bitmap bm ] ) ) ( send dc set-smoothing ' smoothed ) ( send dc set-pen "red" 1 ' solid ) ( send dc translate 0 -1 85 ) ( draw-dachshund dc ) bm

To run the code in this blog post, the pieces must be assembled in this order.