练习 2.51

书本 95 页的 beside 过程将一个框架分成左右两个部分:

e2 of        e2 of
paint-left   paint-right
0.0 , 1.0    0.5 , 1.0
    ^            ^
    |            |
    |            |
    |            |
    | painter1   | painter2
    |            |
    |            |
    |            |
    |            |
    +----------->+-----------> 1.0 , 0.0
0.0 , 0.0    0.5 , 0.0         e1 of
origin        origin           paint-right
of            of
paint-left    paint-right

              &

              e1 of
              paint-left

below 操作和 beside 过程类似,但它将一个框架分成上下两部分:

                            e2 of paint-top
                            0.0 , 1.0
                                ^
                                |
                                |       painter2
origin of paint-top             |
         &           0.0 , 0.5  +------------------------> 1.0 , 0.5
e2 of paint-down                ^                          e1 of
                                |                          paint-top
                                |       painter1
                                |
                                +------------------------> 1.0 , 0.0
                            0.0 , 0.0                      e1 of
                            origin of                      paint-down
                            paint-down

根据这个示意图,给出 below 的定义:

;;; 51-below.scm

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

另一个 below 定义

below 的另一种定义是,不直接使用 transform-painter ,而是通过 beside 过程和 练习 2.50 的旋转过程来完成相关的工作。

以下是画出数字 7 的 painter1 和画出数字 9 的 painter2 的例子:

^            ^                              ^          *****
|            |                              |          *   *
| *********  | *********                    |          *****
|        *   | *       *           ?        |              *
|       *    | *       *         =====>     +------------------------>
|      *     | *********                    ^          *****
|     *      |         *                    |             *
|    *       |         *                    |            *
|   *        |         *                    |           *
+----------->+----------->                  +------------------------>

(beside painter1 painter2)                  (below painter1 painter2)

以下是只使用 beside 和旋转来完成 below 过程的步骤:

1: 分别对 painter1painter2 调用 flip-horiz ,产生新的 painter1painter2
^                                                  ^
|                                                  |
| ********                               ********* |
|       *                                 *        |
|      *            flip-horiz             *       |
|     *            ==============>          *      |
|    *                                       *     |
|   *                                         *    |
+----------->                          <-----------+


^                                                  ^
| *********                              ********* |
| *       *                              *       * |
| *       *         flip-horiz           *       * |
| *********        ==============>       ********* |
|         *                              *         |
|         *                              *         |
|         *                              *         |
+----------->                          <-----------+
2: 分别对新的 painter1painter2 调用 rotate270 ,产生新的 painter1painter2
            ^                           ^
            |                           |
  ********* |                           |        ***
   *        |       rotate270           |    ****  *
    *       |      =============>       | **       *
     *      |                           |          *
      *     |                           |
       *    |                           |
<-----------+                           +----------->


            ^                           ^
  ********* |                           |
  *       * |                           | **********
  *       * |       rotate270           |      *   *
  ********* |      ==============>      |      *   *
  *         |                           |      *****
  *         |                           |
  *         |                           |
<-----------+                           +----------->

3: 使用 beside ,将新的 painter1painter2 组合起来,产生 beside-painter

^            ^
|            |
|        *** | **********
|    ****  * |     *    *
| **       * |     *    *
|          * |     ******
|            |
|            |
+----------->+----------->

4: 对 beside-painter 调用 rotate90 ,产生新的 beside-painter

           *****           ^
           *   *           |
           *****           |
           *               |
<--------------------------+
           *****           ^
            *              |
             *             |
              *            |
<--------------------------+

5: 对新的 beside-painter 调用 flip-horiz ,得出和 below 一样的效果:

^          *****
|          *   *
|          *****
|              *
+-------------------------->
^          *****
|             *
|            *
|           *
+-------------------------->

前面的这五个步骤实际上是一个回溯得出的计算结果,从最后一步往前看,会更容易弄清楚这个 below 的效果是如何实现的。

另外,在对图形进行翻转的时候,我们假设图片是自伸缩的,也即是,它可以自动地根据框架的大小来进行放大和缩小。在一个实际的图形处理语言中,进行翻转的时候,还必须进行缩放,确保图片能正确地显示在给定的框架内。

这个 below 的定义如下:

;;; 51-another-below.scm

(define (below painter1 painter2)
    (lambda (frame)
        ((flip-horiz
            (rotate90
                (beside
                    (rotate270
                        (flip-horiz painter1))
                    (rotate270
                        (flip-horiz painter2)))))
         frame)))

讨论

blog comments powered by Disqus