Overview | Schedule | Resources | Assignments | Home |
By working through the steps in this handout, you will develop a HasCl program to draw a picture made up of many overlapping squares of different sizes and colors.
Shape
type has several other constructors):
data Shape = Poly([(Num, Num)], Color, Color) | Over(Shape, Shape) | Blank;This says that a
Shape
value is either a
polygon, or the combination of one
Shape
over another, or nothing at all. A
polygon needs three parameters--the value Poly(ps, c1, c2)
describes a polygon whose vertices are given by the list ps
,
with border color c1
and interior color c2
.
Each point in the list of vertices is a pair (x, y) :: (Num, Num)
.
The coordinate system of the graphics window (which pops up when you
evaluate an expression of type Shape
) initially has the point
(0, 0)
at the upper-left corner and (200, 200)
at
the lower-right, although this will change as you resize the window,
pan around (click and drag the mouse), or zoom in and out (if you have
a mouse with a scroll wheel). A color is specified as a value of
the following data type, which is also defined in the
graphics module:
data Color = RGBA(Num, Num, Num, Num);The value
RGBA(r, g, b, a)
specifies a color with
red, green, blue, and "alpha" components given by the numbers r, g, b, and a respectively, where each
component ranges from 0 (completely absent) to 255 (full
strength). The alpha level determines the transparency of the color, from
0 for completely transparent to 255 for completely opaque. The graphics module also defines some useful
constants of type Color
; for example,
red
is the value RGBA(255, 0, 0, 255)
(look in the graphics module function browser in Funnie to see what other
colors are defined). There is also a function
RGB :: (Num, Num, Num) -> Color
which makes it easier
to create an opaque color given just the red, green, and blue components.
import std.graphics; square(x, y, r, c) = Poly([(x-r, y-r), (x+r, y-r), (x+r, y+r), (x-r, y+r)], c, c);The
import
declaration is similar to the one in Java--it tells
the compiler that we want to use the definitions from another module (by default,
only definitions in the current module and std.base
are available).
This function will create a polygon with four vertices, giving us a square with
center (x, y)
and half-width r
(like the radius of a
circle--for our purposes, this will be a convenient way to specify a square).
Both the border and the interior will be of color c
.
square(50, 40, 15, RGB(0, 255, 0))
. If you
type this in, the system should pop-up a graphics window
containing the square.
For testing, it will be convenient to define some sample squares. Add each of the following to the source in your module window and compile:
redGiant = square(70, 80, 50, RGB(255, 0, 0)); whiteDwarf = square(20, 50, 10, RGB(255, 255, 255)); purpleMedium = square(60, 40, 30, RGB(128, 0, 128));Now you can easily draw a square by entering its name, e.g.,
redGiant
, in
the module's expression window. However, this only lets you
draw one square at a time. To combine several squares in
one picture, we need the Over
constructor of
the Shape
data type, as follows:
Over(redGiant, purpleMedium)
. Notice how the
squares are combined, and see what happens if you reverse
the order of the squares. For convenience, you may also use
the +++
operator to put one Shape
over
another: try whiteDwarf +++ purpleMedium +++ redGiant
.
Shape
. As usual when
working with a list of things, we will define the function
by recursion. Here is the base case, which uses the special
value Blank
to produce a blank picture:
showShapeList([ ]) = Blank;The recursive case will have the following form:
showShapeList([s : ss]) = ;When this pattern matches,
s
will be the first
shape on the list, and ss
will be a list of
the remaining shapes. Write an appropriate right-hand side
for this case of the function. The shape s
is
already a Shape
; you will need to use
showShapeList
to produce another
Shape
from ss
. These two
Shape
s will then need to be combined into
one with Over
. When you have defined the
function, try it out with showShapeList([redGiant,
whiteDwarf])
.
diagonalSquares(x, y, r, c, 0) = [ ]; diagonalSquares(x, y, r, c, n) = [square(x, y, r, c) : diagonalSquares(x+r, y+r, r, c, n-1)];After entering this function, evaluate
showShapeList(diagonalSquares(30, 30, 10, blue,
9))
. The cases for this function mean that
diagonalSquares(x, y, r, c, n)
will produce
a list of n
squares (because the list is empty
when n
is 0
, and it gets one
extra element for each recursive call as n
counts down to 0
). The first one will have its
center at (x,y)
, with half-width r
and
color c
. Succeeding squares will be offset
by adding r
to the x
and
y
coordinates of the corner; the effect will
be that each square will be centered on the lower-right
corner of the previous one. You should get a picture that
looks like a blue staircase.
vanishingSquares
which is similar to
diagonalSquares
, except replace the size argument
r
in the recursive call (to
vanishingSquares
, of course) with the expression
r*3/4
. To try this out, you will probably want
to start with a larger initial square; something like this
should work: showSquareList(vanishingSquares(30, 30,
20, blue, 7))
++
. Here is a skeleton of the code for you to
fill in:
squareDesign(x, y, r, c, 0) = ; squareDesign(x, y, r, c, n) = [square(x, y, r, c) : squareDesign(x-r, y-r, r/2, c, n-1) ++ squareDesign(x+r, y-r, r/2, c, n-1) ++ squareDesign( ) ++ squareDesign( )];When you have successfully compiled the finished function, try evaluating the following expression:
showShapeList(squareDesign(100, 100, 40, blue, 4))
.
You can change the 4
to
5
to draw one more level, but it will take too
long if you try to do 6 or more levels (each level has four
times as many squares, so there are 1024 squares at level
6).
lessRed
and
lessGreen
, each of type (Color) ->
Color
. Here is one:
lessRed(RGBA(r, g, b, a)) = RGBA(r/2, g, b, a);You will need to enter this and a similar definition for
lessGreen
, then write a new function similar
to squareDesign
that calls these functions in
the appropriate places. Call this new function
colorDesign
, and test it (make sure the initial square
has some red and green in it--for example,
showShapeList(colorDesign(100, 100, 40, white, 5))
).2
; for example, if
you modify colorDesign
, then your new function
should be named colorDesign2
.Overview | Schedule | Resources | Assignments | Home |
DePauw University,
Computer Science Department,
Fall 2006
Maintained by Brian Howard
(bhoward@depauw.edu
).
Last updated