CSC151.01 2009F Functional Problem Solving : Labs

Laboratory: Project Ideas


Summary: In this laboratory, you will explore the three new approaches to making images that were covered in the corresponding reading.

Preparation

Make a copy of project-ideas-lab.scm, which contains much of the code from the reading.

Exercises on Color Trees

Exercise 1: Color Tree Basics

a. What effect do you expect the following instructions to have?

> (define t1 (cons "grey" (cons "red" "black")))
> (define image1 (ctree->image t1 200 200))
> (image-show image1)

b. Check your answer experimentally.

c. What effect do you expect the following instructions to have?

> (define t2 (cons (cons "red" t1) t1))
> (define image2 (ctree->image t2 200 200))
> (image-show image2)

d. Check your answer experimentally.

e. What effect do you expect the followings instruction to have?

> (define image3 (image-new 200 200))
> (image-render-color-tree! image3 t1 0 0 100 100)
> (image-render-color-tree! image3 t1 100 100 50 25)
> (image-render-color-tree! image3 t1 100 150 25 25)
> (image-show image3)

f. Check your answer experimentally.

g. Create one or two color trees of your own and render them.

Exercise 2: New Ways to Render Color Trees

a. The base case for image-render-color-tree! is to render the area as a rectangle. What do you expect to happen if we change the call to image-select-rectangle! to image-select-ellipse!?

b. Check your answer experimentally. Then restore the call to image-select-rectangle!.

c. As written, the width used in recursive calls during horizontal splits is (/ width 2). What do you expect to have happen if we change that to (/ width 2.5)? (Assume we change it for both recursive calls.)

d. Check your answer experimentally. Then restore the original formula.

e. As written, the top edge used in recursive calls for vertical splits is (+ top (/ height 2)). What do you expect to have happend if we use (+ top (/ height 1.5))?

f. Check your answer experimentally. Then restore the original formula.

Exercise 3: A Simple Series of Images

Look at the code for series-1.

a. What do you expect (series-1 5 100 100) to produce?

b. Check your answer experimentally.

c. What do you expect (series-1 42 100 100) to produce?

d. Check your answer experimentally.

e. Do you expect (series-1 43 100 100) to be similar to or very different from the image you got using 42? How do you expect it to differ?

f. Check your answer experimentally.

g. How do you expect (series-1 43 500 500) to differ?

h. Check your answer experimentally.

i. How do you expect (series-1 43 800 100) to relate to the previous two images?

j. Check your answer experimentally.

Exercises on Fractals

Exercise 4: Simple Fractal Activities

a. Use fractal-rectangle! to draw a 200x200 blue rectangle on canvas, using a recursion level of 0.

b. Use fractal-rectangle! to draw a 200x200 red rectangle using a recursion level of 1. (Don't be surprised if it looks pretty boring.)

c. Use fractal-rectangle! to draw a 200x200 green rectangle using a recursion level of 2. (Again, don't be surprised if it's boring.)

d. After those three exercises, you are probably ready to do something a bit more interesting. Here's a modified version of fractal-rectangle! in which we've changed the recursive calls for the top-middle, left-middle, right-middle, and bottom-middle subrectangles so that they use the complement of the color.

(define fractal-rectangle-c!
  (lambda (image color left top right bottom level)
    (cond
      ; Base case: We're at a level in which we just draw the rectangle.
      ((= level 0)
       (context-set-fgcolor! color)
       (image-select-rectangle! image REPLACE
                                left top 
                                (- right left)
                                (- bottom top))
       (image-fill-selection! image)
       (image-select-nothing! image)
       (context-update-displays!))
      ; Recursive case: Break the rectangle into a few parts and recurse
      ; on each.
      (else
       (let* ((midcol1 (round (+ left (/ (- right left) 3))))
              (midcol2 (round (- right (/ (- right left) 3))))
              (midrow1 (round (+ top (/ (- bottom top) 3))))
              (midrow2 (round (- bottom (/ (- bottom top) 3)))))
         ; First row of squares
         (fractal-rectangle-c! image 
                               color
                               left top 
                               midcol1 midrow1
                               (- level 1))
         (fractal-rectangle-c! image 
                               (rgb-complement color)
                               midcol1 top 
                               midcol2 midrow1
                               (- level 1))
         (fractal-rectangle-c! image 
                               color
                               midcol2 top 
                               right midrow1
                               (- level 1))
         ; Second row of squares
         (fractal-rectangle-c! image 
                               (rgb-complement color)
                               left midrow1
                               midcol1 midrow2
                               (- level 1))
         (fractal-rectangle-c! image 
                               color
                               midcol1 midrow1
                               midcol2 midrow2
                               (- level 1))
         (fractal-rectangle-c! image 
                               (rgb-complement color)
                               midcol2 midrow1
                               right midrow2
                               (- level 1))
         ; Third row of squares
         (fractal-rectangle-c! image 
                               color
                               left midrow2
                               midcol1 bottom
                               (- level 1))
         (fractal-rectangle-c! image 
                               (rgb-complement color)
                               midcol1 midrow2
                               midcol2 bottom
                               (- level 1))
         (fractal-rectangle-c! image 
                               color
                               midcol2 midrow2
                               right bottom
                               (- level 1))
         )))))

Put this new version at the end of your definitions pane.

Use this procedure to draw a 200x200 rectangle fractal with black as the initial color and a recursion level of 1. Once you've done that, try it with a recursion level of 2.

e. Predict what will happen if you draw a 200x200 rectangle with yellow as the initial color and a recursion level of 3. Then check your prediction experimentally.

f. Here is a procedure that averages two RGB colors.

;;; Procedure:
;;;   rgb-average
;;; Parameters:
;;;   c1, an RGB color
;;;   c2, an RGB color
;;; Purpose:
;;;   Compute the "average" of two RGB colors.  
;;; Produces:
;;;   c_ave, an RGB color
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   (rgb-red c_ave) is the average of (rgb-red c1) and (rgb-red c2)
;;;   (rgb-green c_ave) is the average of (rgb-green c1) and (rgb-green c2)
;;;   (rgb-blue c_ave) is the average of (rgb-blue c1) and (rgb-blue c2)
(define rgb-average
  (lambda (c1 c2)
    (rgb-new (quotient (+ (rgb-red c1) (rgb-red c2)) 2)
             (quotient (+ (rgb-green c1) (rgb-green c2)) 2)
             (quotient (+ (rgb-blue c1) (rgb-blue c2)) 2))))

And here is a rewritten fractal-rectangle! that averages the colors in the top-middle, left-middle, right-middle, and bottom-middle subrectangles with black and the colors in the other five subrectangles with white.

(define fractal-rectangle-a!
  (lambda (image color left top right bottom level)
    (cond
      ; Base case: We're at a level in which we just draw the rectangle-a.
      ((= level 0)
       (context-set-fgcolor! color)
       (image-select-rectangle! image REPLACE
                                left top 
                                (- right left)
                                (- bottom top))
       (image-fill-selection! image)
       (image-select-nothing! image)
       (context-update-displays!))
      ; Recursive case: Break the rectangle-a into a few parts and recurse
      ; on each.
      (else
       (let* ((midcol1 (round (+ left (/ (- right left) 3))))
              (midcol2 (round (- right (/ (- right left) 3))))
              (midrow1 (round (+ top (/ (- bottom top) 3))))
              (midrow2 (round (- bottom (/ (- bottom top) 3)))))
         ; First row of squares
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-WHITE)
                               left top 
                               midcol1 midrow1
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-BLACK)
                               midcol1 top 
                               midcol2 midrow1
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-WHITE)
                               midcol2 top 
                               right midrow1
                               (- level 1))
         ; Second row of squares
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-BLACK)
                               left midrow1
                               midcol1 midrow2
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-WHITE)
                               midcol1 midrow1
                               midcol2 midrow2
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-BLACK)
                               midcol2 midrow1
                               right midrow2
                               (- level 1))
         ; Third row of squares
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-WHITE)
                               left midrow2
                               midcol1 bottom
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-BLACK)
                               midcol1 midrow2
                               midcol2 bottom
                               (- level 1))
         (fractal-rectangle-a! image 
                               (rgb-average color RGB-WHITE)
                               midcol2 midrow2
                               right bottom
                               (- level 1))
         )))))

g. What do you expect to have happen if we draw a 200x200 level-2 fractal rectangle whose initial color is blue? Check your answer experimentally.

h. What do you expect to have happen if we draw a 200x200 level-3 fractal rectangle whose initial color is green? Check your answer experimentally.

i. Let's change the computation of the intermediate boundaries so that midcol1 is 1/4 of the way across, midcol2 is 1/2 of the way across, midrow1 is 1/4 of the way down, and midrow2 is 1/2 of the way down. Add the following to the end of your definitions pane.

(define fractal-rectangle-u!
  (lambda (image color left top right bottom level)
    (cond
      ; Base case: We're at a level in which we just draw the rectangle-u.
      ((= level 0)
       (context-set-fgcolor! color)
       (image-select-rectangle! image REPLACE
                                left top 
                                (- right left)
                                (- bottom top))
       (image-fill-selection! image)
       (image-select-nothing! image)
       (context-update-displays!))
      ; Recursive case: Break the rectangle-u into a few parts and recurse
      ; on each.
      (else
       (let* ((midcol1 (round (+ left (/ (- right left) 4))))
              (midcol2 (round (+ midcol1 (/ (- right left) 4))))
              (midrow1 (round (+ top (/ (- bottom top) 4))))
              (midrow2 (round (+ midrow1 (/ (- bottom top) 4)))))
         ; First row of squares
         (fractal-rectangle-u! image 
                               (rgb-average color color-white)
                               left top 
                               midcol1 midrow1
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-black)
                               midcol1 top 
                               midcol2 midrow1
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-white)
                               midcol2 top 
                               right midrow1
                               (- level 1))
         ; Second row of squares
         (fractal-rectangle-u! image 
                               (rgb-average color color-black)
                               left midrow1
                               midcol1 midrow2
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-white)
                               midcol1 midrow1
                               midcol2 midrow2
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-black)
                               midcol2 midrow1
                               right midrow2
                               (- level 1))
         ; Third row of squares
         (fractal-rectangle-u! image 
                               (rgb-average color color-white)
                               left midrow2
                               midcol1 bottom
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-black)
                               midcol1 midrow2
                               midcol2 bottom
                               (- level 1))
         (fractal-rectangle-u! image 
                               (rgb-average color color-white)
                               midcol2 midrow2
                               right bottom
                               (- level 1))
         )))))

j. What do you expect to have happen if we draw a 200x200 level-2 fractal rectangle whose initial color is red? Check your answer experimentally. What about a level-3 fractal?

k. Change the computation of the intermediate boundaries so that midcol1 is 1/4 of the way across, midcol2 is 3/4 of the way across, midrow1 is 1/4 of the way down, and midrow2 is 3/4 of the way down.

l. Draw one final level-3 fractal.

Exercise 5: Varying Parameters

Sometimes it is difficult to envision how you make 1000 variations of an image. But, as is often the case, the problem is a bit easier if you break it down into parts. Suppose we want all of our images to be based on the “spin a polygon” technique. In building different images, we can vary

  • the number of sides (that is, the type of polygon);
  • the angle at which the turtle is drawn;
  • the number of copies we draw; and
  • the color we use to draw the polygons.

(We probably can't vary the side length, since that should depend on the size of the image.)

Now, how do we turn one number (the n we're using to describe the image) into four different numbers (or six, if we change the red, green, and blue components separately)? We can use mod

(define series-2 
  (lambda (n width height)
    (let* ((canvas (image-new width height))
           (t (turtle-new canvas))
           (side-length (/ (+ width height) 12))
           (sides (+ 3 (mod n 4)))
           (angle (* 5 (mod n 5)))
           (copies (+ 5 (* 2 (mod n 7))))
           (red (* 256/11 (mod n 11)))
           (green (* 256/13 (mod n 13)))
           (blue (- 256 red)))
      (turtle-set-color! t (rgb-new red green blue))
      (turtle-teleport! t (/ width 3) (/ height 3))
      (turtle-spin-polygon! t side-length sides angle copies)
      (image-show canvas)
      canvas)))

a. Try this procedure with a variety of values for n, width, and height

b. In your own words, explain how the procedure works to vary the drawing.

c. Can we be sure that this procedure creates 1000 different drawings for the values of n from 0 to 999? Why or why not?

Creative Commons License

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright (c) 2007-9 Janet Davis, Matthew Kluber, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)

This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.