Drawing really a lot of love hearts


So we drew and improved a heart once.

But what about drawing a lot of hearts?

1. A table of hearts

In this article we learn how to use lisp mcclim clim's tables

Graphically, you write something like this:

<colgroup> <col class="org-left" /> <col class="org-left" /> <col class="org-left" /> <col class="org-left" /> </colgroup>
formatting-table      
formatting-row formatting-cell    
formatting-row formatting-cell formatting-cell  
formatting-row formatting-cell formatting-cell formatting-cell

This will end up like:


♡♡
♡♡♡

for example.

1.1. Complete set up from last time

So you don't have to go away and come back, here's everything from last time basically. It's not that long. Stay strong.

See the playlist in the comments if you don't know how to set up lisp. You can skim this if you read the articles it's refactored from and jump to SOMETHING-NEW

(progn
  (require :mcclim)
  (require :series)
  (in-package :clim-user)
  (series::install))

1.1.1. Draw one heart []

  1. Heart-bottom outline

    This was guess-and-checked into shape:

    (defparameter *heart-bottom*
      (butlast 
       (let* ((x (scan-range :from (- pi 0.3)
                             :upto (* 2 pi)
                             :by 0.05))
              (x+h (#m+ x (series 0.01)))
              (cosx (#mcos x+h))
              (secx (#M/ x+h))
              (tanx (#mtan x+h))
              (+abs (#Mabs (#M+ secx tanx)))
              (lnx (#mlog +abs)))
         (collect (#Mlist x lnx)))
       3))
    
  2. draw-heart-bottom
    (defun draw-heart-bottom (pane)
      (funcall 'draw-lines* pane
             (apply 'append (butlast *heart-bottom*)))
      (funcall 'draw-lines* pane
           (apply 'append
                  (cdr *heart-bottom*))))
    
  3. draw-heart

    This is just where we got to last time.

    (defun draw-heart (pane &aux (rad 25))
        (with-translation (pane -45 120)
          (with-scaling (pane 28 15)
                (draw-heart-bottom pane)))
      (let ((x (* rad (cos (* pi 1/6))))
              (y (* rad (sin (* pi 1/6)))))
          (with-translation (pane 60 80)
            (draw-circle* pane 0 0 rad :filled nil
                                       :start-angle
                                       (/ pi 6)
                                       :end-angle
                                       (+ pi (/ pi 6))))
    
          (with-translation (pane (+ 60 40) 80)
          (draw-circle* pane 0 0 rad :filled nil
                                     :start-angle
                                     (* pi -1/6)
                                     :end-angle
                                     (- pi (/ pi 6))))))
    
  4. define a frame
    (progn
      (define-application-frame heart ()
      ((current-ink :initform +red+))
      (:pane :application :display-function 'display-function))
      (defun display-function (frame pane)
        (with-slots (current-ink) frame
    
          (With-drawing-options (pane :ink current-ink)
            (draw-heart pane))))
      (defparameter *heart* (make-application-frame 'heart)))
    
  5. Start heart in another thread

    remembering mcclim is thread-safe.

    (bt:make-thread
     (lambda ()
       (run-frame-top-level *heart*)))
    

1.2. SOMETHING-NEW

1.2.1. Draw three hearts

(defun display-function (frame pane)
  (with-slots (current-ink) frame
    (With-drawing-options (pane :ink current-ink)
      (loop :for x :below 30 :by 10 :do
        (with-translation (pane x 0)
          (draw-heart pane))))))
(reinitialize-instance *heart*)

Well, withstanding that looks more evil than romantic.

1.2.2. A table of hearts

(defun heart-table (pane)
  (clim:formatting-table (pane)
    (clim:formatting-row (pane)
      (clim:formatting-cell (pane)
        (draw-heart pane)))
    (clim:formatting-row (pane)
      (clim:formatting-cell (pane)
        (draw-heart pane))
      (clim:formatting-cell (pane)
        (draw-heart pane)))
    (clim:formatting-row (pane)
      (clim:formatting-cell (pane)
        (draw-heart pane))
      (clim:formatting-cell (pane)
        (draw-heart pane))
      (clim:formatting-cell (pane)
        (draw-heart pane)))))
(defun display-function (frame pane)
  (with-slots (current-ink) frame
    (With-drawing-options (pane :ink current-ink)
      (heart-table pane))))
(reinitialize-instance *heart*)

You could write that more concisely, but I think seeing it not-compressed-by-loops makes it clear how the code draws the table. Stay tuned for next time

By the way, can you see how we are creeping up on a game-world-grid.

</div>

Author: screwlisp

Created: 2025-02-02 Sun 10:25

Validate

Get lispmoo2

Comments

Log in with itch.io to leave a comment.

Using lisp and clim at all ; a playlist I made a while ago.