Решение упражнения 2.51 из SICP
Определение below напрямую абсолютно аналогично определению beside. Отличия только в том, как происходит разбиение исходной рамки на две. В beside исходная рамка (0.0, 0.0) - (1.0, 1.0) разбивается на две по вертикали : (0.0, 0.0) - (0.5, 1.0) и (0.5, 0.0) - (1.0, 1.0). В below та же исходная рамка разбивается несколько иначе (по горизонтали): (0.0, 0.0) - (1.0, 0.5) и (0.0, 0.5) - (1.0, 1.0). Соответсвенно меняется split-point и координаты векторов. Результат выглядит так:
(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-bottom frame) (paint-top frame)))))
Теперь более интересная часть - определение below через beside и операции вращения. Несложно заметить, что результат below это почти повернутый на 90 градусов результат beside. Проблема, однако, в этом почти. Изображения в каждой из половин также поворачиваются на 90 градусов, что нам совершенно не нужно. Но эту проблему можно легко решить. Достаточно просто предварительно повернуть каждое из них на 90 градусов в противоположную сторону. На схеме ниже представлено два варианта действий, отличающихся порядком поворотов (по часовой или против часовой стрелки). Кликните на картинке для просмотра в увеличенном виде.
Вспоминая теперь, что поворот на 90 градусов по часовой стрелке - это то же, что поворот на 270 градусов против часовой стрелки, можем записать такие два определения для below:
(define (below painter1 painter2) (rotate-90 (beside (rotate-270 painter1) (rotate-270 painter2))))
(define (below painter1 painter2) (rotate-270 (beside (rotate-90 painter2) (rotate-90 painter1))))
Все просто и красиво.
Write a comment