問題2.49 , 問題2.50 , 問題2.51

(use gl)
(use gl.glut)

(define (make-vect x y)
  (cons x y))

(define (xcor-vect vect)
  (car vect))

(define (ycor-vect vect)
  (cdr vect))

(define (add-vect v1 v2)
  (make-vect (+ (xcor-vect v1) (xcor-vect v2))
             (+ (ycor-vect v1) (ycor-vect v2))))

(define (sub-vect v1 v2)
  (make-vect (- (xcor-vect v1) (xcor-vect v2))
             (- (ycor-vect v1) (ycor-vect v2))))

(define (scale-vect s v)
  (make-vect (* (xcor-vect v) s)
             (* (ycor-vect v) s)))

(define (make-frame origin edge1 edge2)
  (list origin edge1 edge2))
(define (edge1-frame frame) (cadr frame))
(define (edge2-frame frame) (caddr frame))
(define (origin-frame frame) (car frame))

(define (make-segment x y)
  (cons x y))

(define (start-segment x)
  (car x))

(define (end-segment x)
  (cdr x))

(define (frame-coord-map frame)
  (lambda (v)
    (add-vect
     (origin-frame frame)
     (add-vect (scale-vect (xcor-vect v)
                           (edge1-frame frame))
               (scale-vect (ycor-vect v)
                           (edge2-frame frame))))))

(define (segments->painter segment-list)
  (lambda (frame)
    (for-each
     (lambda (segment)
       (draw-line
        ((frame-coord-map frame) (start-segment segment))
        ((frame-coord-map frame) (end-segment segment))))
     segment-list)))

(define (draw-line v1 v2)
  (begin 
    (gl-vertex (xcor-vect v1) (ycor-vect v1))
    (gl-vertex (xcor-vect v2) (ycor-vect v2))))

(define outline
  (segments->painter
   (list
    (make-segment (make-vect 0.0 0.0) (make-vect 0.0 1.0))
    (make-segment (make-vect 0.0 1.0) (make-vect 1.0 1.0))
    (make-segment (make-vect 1.0 1.0) (make-vect 1.0 0.0))
    (make-segment (make-vect 1.0 0.0) (make-vect 0.0 0.0)))))

(define x-line
  (segments->painter
   (list
    (make-segment (make-vect 0.0 0.0) (make-vect 1.0 1.0))
    (make-segment (make-vect 0.0 1.0) (make-vect 1.0 0.0)))))

(define diamond-line
  (segments->painter
   (list
    (make-segment (make-vect 0.5 0.0) (make-vect 1.0 0.5))
    (make-segment (make-vect 1.0 0.5) (make-vect 0.5 1.0))
    (make-segment (make-vect 0.5 1.0) (make-vect 0.0 0.5))
    (make-segment (make-vect 0.0 0.5) (make-vect 0.5 0.0)))))

(define wave
  (segments->painter
   (list
    (make-segment (make-vect 0.5 0.5) (make-vect 0.4 0.25))
    (make-segment (make-vect 0.4 0.25) (make-vect 0.5 0.0))
    (make-segment (make-vect 0.5 0.0) (make-vect 0.6 0.25))
    (make-segment (make-vect 0.6 0.25) (make-vect 0.5 0.5))

    (make-segment (make-vect 0.5 0.5) (make-vect 0.75 0.3))
    (make-segment (make-vect 0.75 0.3) (make-vect 1.0 0.5))
    (make-segment (make-vect 1.0 0.5) (make-vect  0.75 0.7))
    (make-segment (make-vect 0.75 0.7) (make-vect 0.5 0.5))

    (make-segment (make-vect 0.5 0.5) (make-vect 0.7 0.75))
    (make-segment (make-vect 0.7 0.75) (make-vect 0.5 1.0))
    (make-segment (make-vect 0.5 1.0) (make-vect 0.3 0.75))
    (make-segment (make-vect 0.3 0.75) (make-vect 0.5 0.5))

    (make-segment (make-vect 0.5 0.5) (make-vect 0.25 0.4))
    (make-segment (make-vect 0.25 0.4) (make-vect 0.0 0.5))
    (make-segment (make-vect 0.0 0.5) (make-vect 0.25 0.6))
    (make-segment (make-vect 0.25 0.6) (make-vect 0.5 0.5))

    (make-segment (make-vect 0.0 0.0) (make-vect 1.0 1.0)))))

(define (transform-painter painter origin corner1 corner2)
  (lambda (frame)
    (let ((m (frame-coord-map frame)))
      (let ((new-origin (m origin)))
        (painter
         (make-frame new-origin
                     (sub-vect (m corner1) new-origin)
                     (sub-vect (m corner2) new-origin)))))))

(define (flip-vert painter)
  (transform-painter painter
                     (make-vect 0.0 1.0)
                     (make-vect 1.0 1.0)
                     (make-vect 0.0 0.0)))

(define (flip-horiz painter)
  (transform-painter painter
                     (make-vect 1.0 0.0)
                     (make-vect 0.0 0.0)
                     (make-vect 1.0 1.0)))


(define (shrink-to-upper-right painter)
  (transform-painter painter
                     (make-vect 0.5 0.5)
                     (make-vect 1.0 0.5)
                     (make-vect 0.5 1.0)))

(define (rotate90 painter)
  (transform-painter painter
                     (make-vect 1.0 0.0)
                     (make-vect 1.0 1.0)
                     (make-vect 0.0 0.0)))

(define (rotate180 painter)
  (transform-painter painter
                     (make-vect 1.0 1.0)
                     (make-vect 0.0 1.0)
                     (make-vect 1.0 0.0)))

(define (rotate270 painter)
  (transform-painter painter
                     (make-vect 0.0 1.0)
                     (make-vect 0.0 0.0)
                     (make-vect 1.0 1.0)))

(define (squash-inwards painter)
  (transform-painter painter
                     (make-vect 0.0 0.0)
                     (make-vect 0.65 0.35)
                     (make-vect 0.35 0.65)))

(define (beside painter1 painter2)
  (let ((split-point (make-vect 0.5 0.0)))
    (let ((paint-left
           (transform-painter painter1
                              (make-vect 0.0 0.0)
                              split-point
                              (make-vect 0.0 1.0)))
          (paint-right
           (transform-painter painter2
                              split-point
                              (make-vect 1.0 0.0)
                              (make-vect 0.5 1.0))))
      (lambda (frame)
        (paint-left frame)
        (paint-right frame)))))

(define (below painter1 painter2)
  (let ((split-point (make-vect 0.0 0.5)))
    (let ((paint-bottom
           (transform-painter painter1
                              (make-vect 0.0 0.0)
                              (make-vect 1.0 0.0)
                              split-point))
          (paint-top
           (transform-painter painter2
                              split-point
                              (make-vect 1.0 0.5)
                              (make-vect 0.0 1.0))))
      (lambda (frame)
        (paint-top frame)
        (paint-bottom frame)))))

(define (below2 painter1 painter2)
  (rotate90
   (beside (rotate270 painter1)
           (rotate270 painter2))))

(define (split f1 f2)
  (lambda (painter n)
    (if (= n 0)
        painter
        (let ((smaller ((split f1 f2) painter (- n 1))))
        (f1 painter (f2 smaller smaller))))))

(define right-split (split beside below))
(define up-split (split below beside))

(define (square-of-four tl tr bl br)
  (lambda (painter)
    (let ((top (beside (tl painter) (tr painter)))
          (bottom (beside (bl painter) (br painter))))
      (below bottom top))))

(define (corner-split painter n)
  (if (= n 0)
      painter
      (let ((up (up-split painter (- n 1)))
            (right (right-split painter (- n 1))))
        (let ((top-left (beside up up))
              (bottom-right (below right right))
              (corner (corner-split painter (- n 1))))
          (beside (below painter top-left)
                  (below bottom-right corner))))))

;up-split使わない。
(define (corner-split2 painter n)
  (if (= n 0)
      painter
      (let ((right (right-split painter (- n 1)))
            (up (rotate90 (right-split (rotate270 painter) (- n 1)))))
        (let ((top-left (beside up up))
              (bottom-right (below right right))
              (corner (corner-split2 painter (- n 1))))
          (beside (below painter top-left)
                  (below bottom-right corner))))))

;4隅のみ逆に向かせる。
(define (corner-split3 painter n)
  (if (= n 0)
      (flip-horiz painter)
      (let ((up (up-split painter (- n 1)))
            (right (right-split painter (- n 1))))
        (let ((top-left (beside up up))
              (bottom-right (below right right))
              (corner (corner-split3 painter (- n 1))))
          (beside (below painter top-left)
                  (below bottom-right corner))))))

(define (square-limit painter n)
  (let ((quarter (corner-split painter n)))
    (let ((half (beside (flip-horiz quarter) quarter)))
      (below (flip-vert half) half))))

;corner-split2をつかう。
(define (square-limit2 painter n)
  (let ((quarter (corner-split2 painter n)))
    (let ((half (beside (flip-horiz quarter) quarter)))
      (below (flip-vert half) half))))

;square-limitをつかう。
(define (through x) x)
(define (square-limit3 painter n)
  ((square-of-four flip-horiz through
                   rotate180 flip-vert)
   (corner-split painter n)))

;corner-split3をつかう。4隅だけ逆に向かせる。
(define (square-limit4 painter n)
  (let ((quarter (corner-split3 painter n)))
    (let ((half (beside (flip-horiz quarter) quarter)))
      (below (flip-vert half) half))))

(define (main args)
  (glut-init args)
  (glut-init-display-mode GLUT_RGBA)
  (glut-init-window-position 0 0)
  (glut-init-window-size 700 700)
  (glut-create-window "SICP 2.2.4")
  (glut-display-func display)
  (gl-enable GL_LINE_SMOOTH)
  (gl-line-width 0.5)
  (gl-enable GL_BLEND)
  (gl-blend-func GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA)
  (init)
  (glut-main-loop))

(define (display)
  (gl-clear-color 1.0 1.0 1.0 1.0)
  (gl-clear GL_COLOR_BUFFER_BIT)
  (gl-color 1.0 0.0 0.0)
  (gl-begin GL_LINES)
  ((square-limit4 wave 3) (make-frame (make-vect -1 -1) (make-vect 2 0) (make-vect 0 2)))
  (gl-end)
  (gl-flush))

(define (init)
  (gl-clear-color 0.0 0.0 1.0 1.0))
  • 俺実装の方が大分短い。
  • とはいえ柔軟性はSICP実装だなー。