Structure and Interpretation of Computer Programs



Yüklə 2,71 Mb.
Pdf görüntüsü
səhifə48/222
tarix08.08.2018
ölçüsü2,71 Mb.
#61085
1   ...   44   45   46   47   48   49   50   51   ...   222

Representing painters as procedures erects a powerful abstraction barrier in the picture language. We

can create and intermix all sorts of primitive painters, based on a variety of graphics capabilities. The

details of their implementation do not matter. Any procedure can serve as a painter, provided that it

takes a frame as argument and draws something scaled to fit the frame.

28

 

Exercise 2.48.  A directed line segment in the plane can be represented as a pair of vectors -- the



vector running from the origin to the start-point of the segment, and the vector running from the origin

to the end-point of the segment. Use your vector representation from exercise 2.46 to define a

representation for segments with a constructor 

make-segment

 and selectors 

start-segment

 and 

end-segment





Exercise 2.49.  Use 

segments->painter

 to define the following primitive painters:

a.  The painter that draws the outline of the designated frame.

b.  The painter that draws an ‘‘X’’ by connecting opposite corners of the frame.

c.  The painter that draws a diamond shape by connecting the midpoints of the sides of the frame.

d.  The 

wave


 painter. 

Transforming and combining painters

An operation on painters (such as 

flip-vert

 or 


beside

) works by creating a painter that invokes

the original painters with respect to frames derived from the argument frame. Thus, for example, 

flip-vert

 doesn’t have to know how a painter works in order to flip it -- it just has to know how to

turn a frame upside down: The flipped painter just uses the original painter, but in the inverted frame.

Painter operations are based on the procedure 

transform-painter

, which takes as arguments a

painter and information on how to transform a frame and produces a new painter. The transformed

painter, when called on a frame, transforms the frame and calls the original painter on the transformed

frame. The arguments to 

transform-painter

 are points (represented as vectors) that specify the

corners of the new frame: When mapped into the frame, the first point specifies the new frame’s origin

and the other two specify the ends of its edge vectors. Thus, arguments within the unit square specify a

frame contained within the original frame.

(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)))))))

Here’s how to flip painter images vertically: 

(define (flip-vert painter)

  (transform-painter painter

                     (make-vect 0.0 1.0)   ; new origin

                     (make-vect 1.0 1.0)   ; new end of edge1

                     (make-vect 0.0 0.0))) ; new end of edge2



Using 

transform-painter

, we can easily define new transformations. For example, we can

define a painter that shrinks its image to the upper-right quarter of the frame it is given: 

(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)))

Other transformations rotate images counterclockwise by 90 degrees

29

 

(define (rotate90 painter)



  (transform-painter painter

                     (make-vect 1.0 0.0)

                     (make-vect 1.0 1.0)

                     (make-vect 0.0 0.0)))

or squash images towards the center of the frame:

30

 



(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)))

Frame transformation is also the key to defining means of combining two or more painters. The 

beside

 procedure, for example, takes two painters, transforms them to paint in the left and right



halves of an argument frame respectively, and produces a new, compound painter. When the

compound painter is given a frame, it calls the first transformed painter to paint in the left half of the

frame and calls the second transformed painter to paint in the right half of the frame: 

(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)))))

Observe how the painter data abstraction, and in particular the representation of painters as procedures,

makes 


beside

 easy to implement. The 

beside

 procedure need not know anything about the details



of the component painters other than that each painter will draw something in its designated frame.


Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   44   45   46   47   48   49   50   51   ...   222




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə