%Subject: Final PS 3 solutions 
%Date: Tues, 16 Feb 93 12:40:25 EST








Exercise 2.1:

      ---------   ---------   ---------
      |   |   |   |   |   |   |   |  /|
a ->  | 2 | --|-> | 3 | --|-> | 5 | / |
      |   |   |   |   |   |   |   |/  |
      ---------   ---------   ---------


      ---------   ---------   ---------   ---------   ---------   ---------
      |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |  /|
b ->  | 2 | --|-> | 3 | --|-> | 5 | --|-> | 5 | --|-> | 3 | --|-> | 2 | / |
      |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |/  |
      ---------   ---------   ---------   ---------   ---------   ---------

Exercise 2.2:

(procedure->painter (lambda (x y) (* x y)))
 The pattern is composed of rectangular hyperbolas (xy = k) 
 of constant shade, where the shade varies from black (0) to 
 slightly less black (1) from the lower left corner to the 
 upper right. 

(procedure->painter (lambda (x y) (* 255 x y)))
 Again we see rectangular hyperbolas (255xy = k), but now 
 varying in shade from black(0) at the bottom and left edges 
 to white (255) at the top, right point.

Exercise 2.3:

Here's a picture:

  (frame-edge2 frame)
	    ^            |
	    |    P2      |
	    |            |
	    *------------|   * is the new origin of P2 and the
	   ^|            |     new edge 2 for P1
	  / |    P1      |
 origin  /  |            |
 of P2	/   --------------> (frame-edge1 frame)
       /   ^
      /   /
     /   / (frame-origin frame)
     |	/  also origin of P1
     | /
     |/
    (0,0)

Notice that the origin for P1 is the same as the original origin; its
edge 1 is the original edge 1; and its edge 2 is half of the original
edge 2.

Similarly, the origin for P2 is the original origin plus half of the
original edge 2; its edge 1 is the original edge 1; and its edge 2 is
half of the original edge 2.


(define (below p1 p2)
  (lambda (frame)
    (p1 (make-frame
	 (frame-origin frame)
	 (frame-edge1 frame)
	 (vector-scale .5 (frame-edge2 frame))))
    (p2 (make-frame
	 (vector-add (frame-origin frame)
		     (vector-scale .5 (frame-edge2 frame)))
	 (frame-edge1 frame)
	 (vector-scale .5 (frame-edge2 frame))))))

Part 4.2

I wrote this code directly from the diagram in Figure 8.

(a) The new origin is side 1 of the original triangle, but with the
    origin shifted from the old origin to the screen coordinate system
    (the one with origin 0,0):
        (vector-shift (side1 triangle) old-origin zero-vector)
(b) The three arguments to make-triangle are
    - its origin in screen coordinates: new-origin
    - its side 1 relative to its origin, which is just side 2 of the
      original triangle shifted from the old to the new origin:
          (vector-shift (side2 triangle) old-origin new-origin)
    - its side 2 relative to its origin, which is just the origin of
      the original triangle shifted from the old to the new origin.
      Notice that the old origin in the old coordinate system is just
      the zero-vector:
          (vector-shift zero-vector old-origin new-origin)

(define (rotate pict)
  (define (rotated triangle)
    (let ((old-origin (triangle-origin triangle)))
      (let ((new-origin
	     (vector-shift (triangle-side1 triangle) old-origin zero-vector)))
      (pict (make-triangle
	     new-origin
	     (vector-shift (triangle-side2 triangle) old-origin new-origin)
	     (vector-shift zero-vector old-origin new-origin))))))
  rotated)

Part 4.3

All we have to do is draw the drawing in the specified triangle, draw
the rotated drawing in the same triangle, and draw the rotated rotated
drawing in the same triangle:

(define (three-fold drawing)
  (define (tripled triangle)
    (drawing triangle)
    ((rotate drawing) triangle)
    ((rotate (rotate drawing)) triangle))
  tripled)

We can now define 3v and 3band as follows:

(define 3v (three-fold  v-shape))

(define 3band (three-fold  band))


Part 4.4

Here's how I think about the problem.  I would follow the hint and
compute the new origin, O:

  (vector-add (triangle-origin triangle)
	      (vector-add (vector-scale r (triangle-side1 triangle))
			  (vector-scale s (triangle-side2 triangle))))

Then the triangle in which P1 should be drawn has its origin at O and
its sides are the old origin (the zero-vector in the old coordinate
system) and the old side 1.  P2's triangle has its origin at O and its
sides are the old side 1 and side 2.  And P3's triangle has its origin
at O and its sides are the old side 2 and the original origin.

To translate it to code, I noticed that I need to use the old origin
and sides several times, and I need to use these same points in the
new coordinates several times.  So, I use LET to give names to all of
these in the code:

(define (3split p1 p2 p3 r s)
  (define (splitter triangle)

;;; In the old coordinate system, we have: 
    (let ((old-origin (triangle-origin triangle))
	  (old-side1 (triangle-side1 triangle))
	  (old-side2 (triangle-side2 triangle)))

;;;The common origin for the three triangles, O, is computed as stated before: 
      (let ((O (vector-add old-origin
			   (vector-add (vector-scale r old-side1)
				       (vector-scale s old-side2)))))

;;;The vertices of the original triangle, in the new coordinate system 
;;;(with O as origin) are:
	(let ((new-origin (vector-shift zero-vector old-origin O))
	      (new-side1 (vector-shift old-side1 old-origin O))
	      (new-side2 (vector-shift old-side2 old-origin O)))
	  (P1 (make-triangle O new-origin new-side1))
	  (P2 (make-triangle O new-side1 new-side2))
	  (P3 (make-triangle O new-side2 new-origin))))))
  splitter)

With r + s > 1, the new origin is positioned outside the original triangle.
Because of this the three smaller triangles (and hence the pictures in them) overlap.

Part 4.5

make-splitter is very much like 3split, but it takes the arguments at
a different time.  This is a common pattern in Scheme, and is easily
expressed:

(define (make-splitter r s)
  (lambda (p)
    (3split p p p r s)))

To test it, I tried the following:

  (define equal-split (make-splitter (/ 1 3) (/ 1 3)))
  (draw g2 (equal-split (superimpose outline-drawing v-shape)))

Part 4.6

Repeating the same idea as in 4.5, I get:

(define (make-rec-splitter r s)
  (define (split pict levels)
    (if (= levels 0)
	pict
	(let ((p (split pict (-1+ levels))))
	  (3split p p p r s))))
  split)

Part 4.7

This is somewhat more difficult, because the triangles don't have a
common origin.  Still, we can define the points q, r, and s in the old
coordinate system and then create triangles for each of the pictures.

(define (4split p1 p2 p3 p4 q r s)
  (lambda (triangle)
    (let ((orig (triangle-origin triangle))
	  (s1 (triangle-side1 triangle))
	  (s2 (triangle-side2 triangle)))
      (let ((s1-absolute (vector-shift s1 orig zero-vector))  ;;origin for P1
	    (s2-absolute (vector-shift s2 orig zero-vector))) ;;origin for P4
	(let ((q-pt (vector-scale q s1))  ;;point q on side 1
	      (r-pt (vector-scale r s2))  ;;point r on side 2
	      (s-pt (vector-add (vector-scale s s1)   ;;point s on the third side
				(vector-scale (- 1 s) s2))))
	  (let ((q-absolute (vector-shift q-pt orig zero-vector))) ;;org for P3

;;To make the 4 new triangles, we appropriately shift q-pt, r-pt, and s-pt from the 
;;origin of the main triangle to the respective origins of the new triangles. 
	    (p1 (make-triangle s1-absolute
			       (vector-shift q-pt orig s1-absolute)
			       (vector-shift s-pt orig s1-absolute)))
	    (p2 (make-triangle orig q-pt r-pt))  ;;P2 has "orig" for its origin
	    (p3 (make-triangle q-absolute
			       (vector-shift s-pt orig q-absolute)
			       (vector-shift r-pt orig q-absolute)))
	    (p4 (make-triangle s2-absolute
			       (vector-shift r-pt orig s2-absolute)
			       (vector-shift s-pt orig
					     s2-absolute)))))))))


The analogues for make-splitter, make-rec-splitter and rec-equal-split
can now be written using 4split.

(define (make-4-splitter q r s)
  (lambda (p) (4split p p p p q r s)))

(define (make-rec-4-splitter q r s)
  (define (splitter pict levels)
    (if (= levels 0)
	pict
	(let ((p (splitter pict (-1+ levels))))
	  (4split p p p p q r s))))
  splitter)

(define rec-equal-4split (make-rec-4-splitter (/ 1 2) (/ 1 2) (/ 1 2)))


Part 4.8

See the sample drawings attached.

Part 4.9

The only two other operations on vectors are the two selectors,
vector-xcor and vector-ycor.  Everything else is written in terms of
these, so we only need to make the following changes:

(define vector-xcor car)   ;; Unchanged
(define vector-ycor cadr)  ;; Was CDR, not CADR







