Posted January 31, 2025 by screwtape
#common lisp #McCLIM #Valentine's day #Heart #Drawing #Programming #LISP #Tutorial #Easy
*Prepare for valentine's day by drawing a heart with LISP McCLIM!
I'm not an artist. Prahou is the show artist.
Setting-stuff-up I'll link in an appendix. Let's just roll into some lisp.
I guess you got into lisp using M-x slime in emacs or $ sbcl in shell.
(ql:quickload :mcclim)
(in-package :clim-user)
This package is nicely set up for being a user of clim.
(define-application-frame heart () ((current-ink :initform +red+)) (:pane :application :display-function 'display-function))
=+red+=
has red ink inside of it.
We can incrementally change clim stuff by
If you're not playing along properly, remember that lisp, and particularly clim interactively and semi/automatically handle "errors" very, very well. Nothing bad happens, ever.
It's a bit random, but this is just what display-function(s) do:
(defun display-function (frame pane) (draw-circle* pane 60 80 25))
(find-application-frame 'heart)
congratulations. I guess we should use that blue ink. Here we begin just redefining display-function over and over. Sure, whatever better way you just thought of is better.
(defun display-function (frame pane) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (draw-circle* pane 60 80 25))))
and try it again
(find-application-frame 'heart)
Okay! Moving on up in this world.
(defun display-function (frame pane) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (draw-circle* pane 60 80 25) (draw-circle* pane 100 80 25))))
and try it again
(find-application-frame 'heart)
Er, let's move these circles differently for clarity. And let's make them not filled and things.
(defun display-function (frame pane) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (with-translation (pane 0 0) (draw-circle* pane 60 80 25 :filled nil)) (with-translation (pane 40 0) (draw-circle* pane 60 80 23 :filled nil)))))
(defun display-function (frame pane) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (with-translation (pane 0 0) (draw-circle* pane 60 80 25 :filled nil :start-angle 0.0 :end-angle (+ pi (/ pi 6)))) (with-translation (pane 40 0) (draw-circle* pane 60 80 25 :filled nil :start-angle (* pi -1/6) :end-angle pi)))))
Well, hey, we got into some math stuff after all. Er, with a radius of 25, I guess
(list (* rad (cos (* pi 1/6))) (* rad (sin (* pi 1/6))))
21.65063509461097d0 | 12.499999999999998d0 |
We can tell intuitively what directions we have to go these magnitudes in.
(defun display-function (frame pane &aux (rad 25)) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (with-translation (pane 60 80) (draw-circle* pane 0 0 rad :filled nil :start-angle 0.0 :end-angle (+ pi (/ pi 6))) (destructuring-bind (x y) (list (* rad (cos (* pi 1/6))) (* rad (sin (* pi 1/6)))) (let* ((dx (+ (* 2 rad) (- (* 2 (- rad x)) ))) (dy (* dx (- (/ x y))))) (draw-line* pane (- x) y (+ (- x) dx) (+ y (- dy)))) )) (with-translation (pane (+ 60 40) 80) (draw-circle* pane 0 0 rad :filled nil :start-angle (* pi -1/6) :end-angle pi) (destructuring-bind (x y) (list (* rad (cos (* pi 1/6))) (* rad (sin (* pi 1/6)))) (let* ((dx (+ (* 2 rad) (- (* 2 (- rad x)) ))) (dy (* dx (- (/ x y))))) (draw-line* pane (+ x) y (- x dx) (+ y (- dy)))))) )))
(defun display-function (frame pane &aux (rad 25)) (with-slots (current-ink) frame (with-drawing-options (pane :ink current-ink) (with-translation (pane 60 80) (draw-circle* pane 0 0 rad :filled nil :start-angle (/ pi 6) :end-angle (+ pi (/ pi 6))) (destructuring-bind (x y) (list (* rad (cos (* pi 1/6))) (* rad (sin (* pi 1/6)))) (let* ((dx (+ (* 2 rad) (- (* 2 (- rad x)) ))) (dy (* dx (- (/ x y))))) (draw-line* pane (- x) y (+ (- x) dx) (+ y (- dy)))) )) (with-translation (pane (+ 60 40) 80) (draw-circle* pane 0 0 rad :filled nil :start-angle (* pi -1/6) :end-angle (- pi (/ pi 6))) (destructuring-bind (x y) (list (* rad (cos (* pi 1/6))) (* rad (sin (* pi 1/6)))) (let* ((dx (+ (* 2 rad) (- (* 2 (- rad x)) ))) (dy (* dx (- (/ x y))))) (draw-line* pane (+ x) y (- x dx) (+ y (- dy)))))) )))
I'm giving myself a solid 6 out of 10 for valentines day.