PasteRack.org
Paste # 96369
2017-10-13 18:41:37

Forked from paste # 83688.

Fork as a new paste.

Paste viewed 87 times.


Embed:

happy-cat

  1. #lang racket
  2.  
  3. (require pict racket/draw)
  4.  
  5. ;; Not exported by pict/private/utils.rkt
  6. (define (draw-shape/border w h draw-fun
  7.                              color [border-color #f] [border-width #f]
  8.                              #:draw-border? [draw-border? #t]
  9.                              #:transparent? [transparent? #f])
  10.     (dc (λ (dc dx dy)
  11.           (define old-brush (send dc get-brush))
  12.           (define old-pen   (send dc get-pen))
  13.           (send dc set-brush
  14.                 (send the-brush-list find-or-create-brush
  15.                       (cond [transparent? "white"]
  16.                             [color        color]
  17.                             [else         (send old-pen get-color)])
  18.                       (if transparent? 'transparent 'solid)))
  19.           (if draw-border?
  20.               (when (or border-color border-width)
  21.                 ;; otherwise, leave pen as is
  22.                 (send dc set-pen (send the-pen-list
  23.                                        find-or-create-pen
  24.                                        (or border-color
  25.                                            (send old-pen get-color))
  26.                                        (or border-width
  27.                                            (send old-pen get-width))
  28.                                        (send old-pen get-style))))
  29.               (send dc set-pen "black" 1 'transparent))
  30.           (draw-fun dc dx dy)
  31.           (send dc set-brush old-brush)
  32.           (send dc set-pen   old-pen))
  33.         w h))
  34.  
  35. (define (circumscribed-triangle width height
  36.         #:angle0 [angle0 (/ pi 2)]
  37.         #:angle1 [angle1 (+ angle0 (* 2/3 pi))]
  38.         #:angle2 [angle2 (+ angle1 (* 2/3 pi))]
  39.         #:color [color #f]
  40.         #:border-color [border-color #f]
  41.         #:border-width [border-width #f])
  42.   (draw-shape/border width height
  43.                      (λ (dc dx dy)
  44.                        (define radius (/ (min width height) 2))
  45.                        (send dc draw-polygon
  46.                              (list (make-object point% (+ dx (* radius (cos angle0))) (- dy (* radius (sin angle0))))
  47.                                    (make-object point% (+ dx (* radius (cos angle1))) (- dy (* radius (sin angle1))))
  48.                                    (make-object point% (+ dx (* radius (cos angle2))) (- dy (* radius (sin angle2)))))
  49.                              (/ width 2) (/ height 2)))
  50.                      color border-color border-width
  51.                      #:draw-border? (or border-color border-width)
  52.                      #:transparent? #f))
  53.  
  54. (define (isoceles-triangle width height
  55.                            #:angle [angle 0]
  56.                            #:color [color #f]
  57.                            #:border-color [border-color #f])
  58.   (circumscribed-triangle width height
  59.                           #:angle0 (+ (/ pi 2) angle)
  60.                           #:angle1 (+ angle (* 4/3 pi))
  61.                           #:angle2 (+ angle (* 5/3 pi))
  62.                           #:color color #:border-color border-color
  63.                           #:border-width (and border-color 1)))
  64.  
  65.  
  66. (define (equilateral-triangle width height
  67.                               #:angle [angle 0]
  68.                               #:color [color #f]
  69.                               #:border-color [border-color #f])
  70.   (circumscribed-triangle width height
  71.                           #:angle0 (+ (/ pi 2) angle)
  72.                           #:angle1 (+ (/ pi 2) angle (* 2/3 pi))
  73.                           #:angle2 (+ (/ pi 2) angle (* 4/3 pi))
  74.                           #:color color #:border-color border-color
  75.                           #:border-width (and border-color 1)))
  76.  
  77. (define (polar r θ)
  78.   (cons (* r (cos θ)) (* r (sin θ))))
  79.  
  80. (define (cat-silhouette radius ;; radius of the cat face
  81.                         ;; How much farther than the circle does the ear extend?
  82.                         #:left-ear-extent [left-ear-extent (/ radius 2)]
  83.                         ;; How much of an arc does the ear sweep out?
  84.                         #:left-ear-arc [left-ear-arc (* pi 1/4)]
  85.                         ;; At what angle do we start drawing the ear?
  86.                         #:left-ear-angle [left-ear-angle (- (* 2/3 pi) (/ left-ear-arc 2))]
  87.                         #:right-ear-extent [right-ear-extent (/ radius 2)]
  88.                         #:right-ear-arc [right-ear-arc (* pi 1/4)]
  89.                         #:right-ear-angle [right-ear-angle (- (* 1/3 pi) (/ right-ear-arc 2))]
  90.                         #:color [color "orange"]
  91.                         #:border-color [border-color (make-object color% 200 80 100)]
  92.                         #:border-width [border-width 1])
  93.   (when (> (+ left-ear-arc right-ear-arc) (* 2 pi))
  94.     (error 'cat-silhouette "Ear arcs cannot exceed 2pi"))
  95.   (when (> (+ right-ear-angle right-ear-arc) left-ear-angle)
  96.     (error 'cat-silhouette "Right ear cannot overlap with left ear"))
  97.   (when (> (+ left-ear-angle left-ear-arc) (+ (* 2 pi) right-ear-angle))
  98.     (error 'cat-silhouette "Left ear cannot overlap with right ear"))
  99.  
  100.   (define left-ear-tip
  101.     (polar (+ left-ear-extent radius) (+ left-ear-angle (/ left-ear-arc 2))))
  102.   (define right-ear-tip
  103.     (polar (+ right-ear-extent radius) (+ right-ear-angle (/ right-ear-arc 2))))
  104.  
  105.   ;; All calculations done in cat-face-center-is-(0,0) coordinates.
  106.   (define left-protrusion
  107.     (min (- radius) (car left-ear-tip) (car right-ear-tip)))
  108.   (define right-protrusion
  109.     (max radius (car right-ear-tip) (car left-ear-tip)))
  110.   (define top-protrusion
  111.     (max radius (cdr left-ear-tip) (cdr right-ear-tip)))
  112.   (define bottom-protrusion
  113.     (min (- radius) (cdr left-ear-tip) (cdr right-ear-tip)))
  114.  
  115.   ;; All protrusions affect what the overall coordinate space is.
  116.   ;; If an ear extends past the leftmost or topmost extent of the base circle,
  117.   ;; then all coordinates must be adjusted by the difference from the circle.
  118.   ;; If an ear extends past the rightmost or bottommost extent of the circle,
  119.   ;; that difference (plus the left/top difference) add to the width and
  120.   ;; height of the image.
  121.   ;; The left and top protrusions are what shift our coordinate space.
  122.   ;; The right and bottom protrusions possibly add to the overall width
  123.   ;; and height.
  124.   (define adjust-left (+ (- (max 0 (+ left-protrusion radius)))
  125.                          (or border-width 0)))
  126.   (define adjust-top (max 0 (- (+ (or border-width 0) top-protrusion) radius)))
  127.  
  128.   (define (from-cat-coords point)
  129.     (match-define (cons x y) point)
  130.     (cons (+ x adjust-left radius) (- (+ radius adjust-top) y)))
  131.  
  132.   (define left-ear-end
  133.     (from-cat-coords
  134.     (polar radius (+ left-ear-angle left-ear-arc))))
  135.   (define right-ear-end
  136.     (from-cat-coords
  137.      (polar radius (+ right-ear-angle right-ear-arc))))
  138.  
  139.   (define width
  140.     (+ adjust-left radius right-protrusion (or border-width 0)))
  141.   (define height
  142.     (+ adjust-top radius (- bottom-protrusion) (or border-width 0)))
  143.   (values
  144.   (draw-shape/border width
  145.                      height
  146.                      (λ (dc dx dy)
  147.                        (define diameter (* radius 2))
  148.                        (define cat-path (new dc-path%))
  149.                        (send cat-path arc
  150.                              (+ adjust-left dx) (+ adjust-top dy)
  151.                              diameter diameter
  152.                              (+ left-ear-angle left-ear-arc)
  153.                              right-ear-angle)
  154.                        (send cat-path lines
  155.                              (list (from-cat-coords right-ear-tip)
  156.                                    right-ear-end))
  157.                        (send cat-path arc
  158.                              (+ adjust-left dx) (+ adjust-top dy)
  159.                              diameter diameter
  160.                              (+ right-ear-angle right-ear-arc)
  161.                              left-ear-angle)
  162.                        (send cat-path lines
  163.                              (list (from-cat-coords left-ear-tip)
  164.                                    left-ear-end))
  165.                        (send cat-path close)
  166.                        (send dc draw-path cat-path dx dy))
  167.                      color border-color border-width
  168.                      #:draw-border? border-width
  169.                      #:transparent? #f)
  170.   from-cat-coords))
  171.  
  172. (define (happy-eyes width height
  173.                     #:boldness [boldness 0.2]
  174.                     #:color [color "black"]
  175.                     #:border-color [border-color "black"]
  176.                     #:border-width [border-width #f])
  177.   ;; More boldness = less height for the smaller ellipse.
  178.   (define height-percent (- 1 boldness))
  179.   (unless (< 0 boldness 1)
  180.           (error 'happy-eyes "Boldness must be between 0 and 1 exclusive"))
  181.   (draw-shape/border width height
  182.     (lambda (dc dx dy)
  183.       (define eye-path (new dc-path%))
  184.       (send eye-path arc dx dy width height 0 pi)
  185.       (send eye-path arc dx (+ dy (* height boldness))
  186.             width (* height height-percent) pi 0 #f)
  187.       (send eye-path close)
  188.       (send dc draw-path eye-path dx dy))
  189.       color border-color border-width
  190.       #:draw-border? border-width
  191.       #:transparent? #f))
  192.  
  193. (define (standard-cat radius
  194.                       #:left-ear-extent [left-ear-extent (/ radius 2)]
  195.                       #:left-ear-arc [left-ear-arc (* pi 1/4)]
  196.                       #:left-ear-angle [left-ear-angle (- (* 2/3 pi) (/ left-ear-arc 2))]
  197.                       #:right-ear-extent [right-ear-extent (/ radius 2)]
  198.                       #:right-ear-arc [right-ear-arc (* pi 1/4)]
  199.                       #:right-ear-angle [right-ear-angle (- (* 1/3 pi) (/ right-ear-arc 2))]
  200.                       #:fur-color [fur-color "orange"]
  201.                       #:fur-border-color [fur-border-color (make-object color% 200 80 100)]
  202.                       #:eye-color [eye-color "black"]
  203.                       #:nose-color [nose-color "pink"]
  204.                       #:nose [nose (equilateral-triangle (/ radius 2) (/ radius 2) #:angle pi #:color nose-color)]
  205.                       #:happy? [happy? #f]
  206.                       #:eyes [eyes
  207.                               (if happy?
  208.                                   (happy-eyes (/ radius 3) (/ radius 3) #:color eye-color)
  209.                                   (filled-ellipse (/ radius 3) (/ radius 3) #:color eye-color))]
  210.                       #:left-eye [left-eye #f]
  211.                       #:right-eye [right-eye #f]
  212.                       #:border-width [border-width 1])
  213.   (define radius2 (* 1/2 radius))
  214.   (define-values (face coord-fn)
  215.     (cat-silhouette radius
  216.                     #:left-ear-extent left-ear-extent
  217.                     #:left-ear-arc left-ear-arc
  218.                     #:left-ear-angle left-ear-angle
  219.                     #:right-ear-extent right-ear-extent
  220.                     #:right-ear-arc right-ear-arc
  221.                     #:right-ear-angle right-ear-angle
  222.                     #:color fur-color
  223.                     #:border-color fur-border-color
  224.                     #:border-width border-width))
  225.   (match-define (cons center-x center-y) (coord-fn (cons 0 0)))
  226.  
  227.   (define face-and-nose
  228.   (pin-over face
  229.             (- center-x (/ (pict-width nose) 2))
  230.             (- center-y (/ (pict-height nose) 2))
  231.             nose))
  232.  
  233.   (define lip
  234.     (draw-shape/border radius2 radius2
  235.                      (λ (dc dx dy)
  236.                        (send dc draw-arc dx dy radius2 radius2 pi 0))
  237.                      fur-color fur-border-color 1))
  238.  
  239.   (define left-lip
  240.     (pin-over face-and-nose
  241.               (- center-x (pict-width lip))
  242.               center-y
  243.               lip))
  244.  
  245.   (define lips
  246.     (pin-over left-lip center-x center-y lip))
  247.  
  248.   (define select-left-eye (or left-eye eyes))
  249.   (define with-left-eye
  250.     (pin-over lips
  251.               (- center-x (pict-width select-left-eye) (/ (pict-width nose) 2))
  252.               (- center-y (pict-height nose))
  253.               select-left-eye))
  254.  
  255.   (pin-over with-left-eye
  256.             (+ center-x (/ (pict-width nose) 2))
  257.             (- center-y (pict-height nose))
  258.             (or right-eye eyes)))
  259.  
  260. (standard-cat 50)
  261. (standard-cat 50 #:happy? #t)

=>

image

image