Fundamentals of Computer Science I: Media Computing (CS151.02 2007F)
Primary: [Front Door] [Glance] - [Academic Honesty] [Instructions]
Current: [Outline] [EBoard] [Reading] [Lab] [Assignment]
Groupings: [Assignments] [EBoards] [Examples] [Exams] [Handouts] [Labs] [Outlines] [Projects] [Readings] [Reference]
Reference: [Scheme Report (R5RS)] [Scheme Reference] [DrScheme Manual]
Related Courses: [CSC151.01 2007F (Davis)] [CSC151 2007S (Rebelsky)] [CSCS151 2005S (Stone)]
Due: 4 p.m., Tuesday, 20 November 2007
Summary: In this assignment, you will explore some potentially interesting variants of a technique for designing images called fractals.
Purposes: To help you think more about deep recursion (a technique in which you do multiple recursive calls per procedure call). To give you one final chance to explore techniques for making images before you begin your project.
Expected Time: Two to three hours.
Collaboration: We encourage you to work in groups of size three. You may, however, work alone or work in a group of size two or size four. You may discuss this assignment with anyone, provided you credit such discussions when you submit the assignment.
Submitting:
Email your answer to <rebelsky@grinnell.edu>
. The title of your email
should have the form CSC151.02 2007F Assignment 15
and
should contain your answers to all parts of the assignment. Scheme code
should be in the body of the message.
Warning: So that this assignment is a learning experience for everyone, we may spend class time publicly critiquing your work.
One of the more mathematically interesting kinds of drawings is what is commonly called a fractal. Fractals are self-similar drawings. That is, each portion of the drawing bears some resemblance to the larger drawing. We normally draw fractals by breaking the larger drawing into equal portions and drawing each portion using the same technique.
For example, to draw an NxM rectangle, we might draw nine (N/3)x(M/3) rectangles in a grid. Similarly, to draw each of those nine rectangles, we might draw nine (N/9)x(M/9) rectangles, and so on and so forth. When do we stop? When we've recursed enough of when the rectangles are small enough.
We might express this technique in code as follows.
;;; Procedure: ;;; fractal-rectangle! ;;; Parameters: ;;; image, an image ;;; color, the desired color of the rectangle ;;; left, the left edge of the rectangle ;;; top, the top edge of the rectangle ;;; width, the width of the rectangle ;;; height, the height of the rectangle ;;; level, the level of recursion ;;; Purpose: ;;; Draw a "fractal" version of the rectangle by ;;; breaking the rectangle up into subrectangles, ;;; and recursively drawing some of those rectangles ;;; (potentially in different colors). When does ;;; recursion stop? When the level of recursion is 0. ;;; Produces: ;;; [Nothing; Called for the side effect] (define fractal-rectangle! (lambda (image color left top right bottom level) (cond ((= level 0) (envt.set-fgcolor! color) (image.select-rectangle! image selection.replace left top (- right left) (- bottom top)) (image.fill! image) (image.select-nothing! image) (envt.update-displays!)) (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! image color left top midcol1 midrow1 (- level 1)) (fractal-rectangle! image color midcol1 top midcol2 midrow1 (- level 1)) (fractal-rectangle! image color midcol2 top right midrow1 (- level 1)) ; Second row of squares (fractal-rectangle! image color left midrow1 midcol1 midrow2 (- level 1)) (fractal-rectangle! image color midcol1 midrow1 midcol2 midrow2 (- level 1)) (fractal-rectangle! image color midcol2 midrow1 right midrow2 (- level 1)) ; Third row of squares (fractal-rectangle! image color left midrow2 midcol1 bottom (- level 1)) (fractal-rectangle! image color midcol1 midrow2 midcol2 bottom (- level 1)) (fractal-rectangle! image color midcol2 midrow2 right bottom (- level 1)) )))))
Why would we use such a technique, since all we end up with is the same rectangle? Well, things get a bit interesting when you make subtle changes (other than just the level of recursion) at each recursive call. Most typically, you might draw the different subrectangles in modified versions of the original color. Once you do that, you can also think about changing whether or not you use an even grid, or even whether or not you draw each sub-rectangle.
The technique sounds simple, but it can produce some very interesting images. More generally, fractals also let us provide interesting simulations of many natural objects, such as trees, mountains, and coastlines, that have some of the same self-similarity. We'll start our explorations with these rectangles.
In order to best understand how fractal drawing of rectangles works,
it will be useful for you to practice a bit with variants of the
fractal-rectangle!
procedure.
a. We'll start with the plain version of the procedure. Create a
200x200 image, call it canvas, and use
fractal-rectangle!
to draw a 200x200 blue rectangle
using a recursion level of 0.
b. Next, 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. Next, 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. Change the recursive calls for the top-middle, left-middle, right-middle, and bottom-middle subrectangles so that they use the complement of the color. Then, 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. Check your prediction experimentally.
f. Here is a procedure that averages two colors.
;;; Procedure: ;;; rgb.average ;;; Parameters: ;;; color1, an RGB color ;;; color2, an RGB color ;;; Purpose: ;;; Averages color1 and color2 ;;; Produces: ;;; average, an RGB color ;;; Preconditions: ;;; [None; called for the side effect] ;;; Postconditions: ;;; (rgb.red average) is the average of ;;; (rgb.red color1) and (rgb.red color2) ;;; (rgb.green average) is the average of ;;; (rgb.green color1) and (rgb.green color2) ;;; (rgb.blue average) is the average of ;;; (rgb.blue color1) and (rgb.blue color2) (define rgb.average (lambda (color1 color2) (rgb.new (* 0.5 (+ (rgb.red color1) (rgb.red color2))) (* 0.5 (+ (rgb.green color1) (rgb.green color2))) (* 0.5 (+ (rgb.blue color1) (rgb.blue color2))))))
Rewrite fractal-rectangle!
so that the colors in
the top-middle, left-middle, right-middle, and bottom-middle subrectangles
are averaged with black and the colors in the other five subrectangles
are averaged with white.
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. 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.
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.
Okay, you're finally done with the preparation. On to the assignment.
A. Using the basic ideas presented
above, rewrite fractal-rectangle!
to make the most
interesting image that you can. You might change the size of the
subrectangles, the function used to compute their colors, or even the
number of subrectangles.
B. In addition, write a procedure,
random-fractal-rectangle!
, that behaves much
like fractal-rectangle!
except that at least one of
the
computations (e.g., of the columns, rows, and/or colors) involves a
random number.
You may have noticed that level-3 fractals can take quite a while to draw. In your experiments, you may want to try your code with recursion levels of 1 and 2 to see what it looks like before trying recursion level 3.
We will judge your procedures both on the quality of the images they produce and on the cleverness of your modifications to the code.
Primary: [Front Door] [Glance] - [Academic Honesty] [Instructions]
Current: [Outline] [EBoard] [Reading] [Lab] [Assignment]
Groupings: [Assignments] [EBoards] [Examples] [Exams] [Handouts] [Labs] [Outlines] [Projects] [Readings] [Reference]
Reference: [Scheme Report (R5RS)] [Scheme Reference] [DrScheme Manual]
Related Courses: [CSC151.01 2007F (Davis)] [CSC151 2007S (Rebelsky)] [CSCS151 2005S (Stone)]
Copyright © 2007 Janet Davis, Matthew Kluber, and Samuel A. Rebelsky. (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.