Parametric Curves
We're now going to learn another tool for creating interesting shapes, called a parametric curve or parametric equation. A parametric curve is a function from some input (the parameter in "parametric") to a point. For example, a parametric equation for a circle might have as its input an angle and it would give us the point on the circle at that angle. In Scala we could write
def parametricCircle(angle: Angle): Point =
Point(100, angle)
choosing the arbitrary value of 100
as the radius.
The input to a parametric curve tells us how far along the curve we are. In the example of a circle above, the input would start at 0 degrees and finish at 360 degrees.
If we choose lots of different values for the input, and then draw a shape at each point we get back from the parametric equation, we can suggest the shape of the parametric curve. The example below shows this, choosing twelve evenly spaced angles and drawing a circle at each point. As you should notice, this is very similar to how we went about creating polygons.
Exercise: Drawing a Parametric Curve
Implement a method drawCurve
with the skeleton below.
def drawCurve(points: Int, marker: Image, curve: Angle => Point): Image =
???
The parameters have the following meaning:
points
is the number of evenly spaced points around the circle from which we're sampling the parametric curve;marker
is theImage
we draw at each point we sample from the circle; andcurve
is the parametric curve.
Use this to draw points around the parametric circle, as shown above.
This is a modification of code we wrote in the previous chapter. It's also a structural recursion over the natural numbers.
def drawCurve(points: Int, marker: Image, curve: Angle => Point): Image = {
// Angle.one is one complete turn. I.e. 360 degrees
val turn = Angle.one / points
def loop(count: Int): Image = {
count match {
case 0 => marker.at(curve(Angle.zero))
case n =>
marker.at(curve(turn * count)).on(loop(n - 1))
}
}
loop(points)
}
Exercise: Parametric Spirals
Let's now see a little bit of what we can do with parametric curves. To create a circle we keep the radius constant as the angle increases. If, instead, the radius increases as the angle increases we'll get a spiral. (How quickly should the radius increase? It's up to you! Different choices will give you different spirals.)
Implement a function or method parametricSpiral
that creates a spiral.
Here's a type of spiral, known as a logarithmic spiral, that has a particularly pleasing shape. Draw it and see for yourself!
def parametricSpiral(angle: Angle): Point =
Point((Math.exp(angle.toTurns) - 1) * 200, angle)
Exercise: Expressive Drawing
Modify drawCurve
so that marker
is a function from Point
to Image
. The point passed to marker
should be the point produced by the parametric curve. This allows the marker image to depend on the point so we can, for example, make the marker image bigger as the radius increases, or change its color in response to the angle. The picture below shows an example using this new expressivity.
This is a small modification to drawCurve
.
def drawCurve(
points: Int,
marker: Point => Image,
curve: Angle => Point
): Image = {
// Angle.one is one complete turn. I.e. 360 degrees
val turn = Angle.one / points
def loop(count: Int): Image = {
count match {
case 0 =>
val pt = curve(Angle.zero)
marker(pt).at(pt)
case n =>
val pt = curve(turn * count)
marker(pt).at(pt).on(loop(n - 1))
}
}
loop(points)
}
Here's how I created the example image using the new version of drawCurve
.
val marker = (point: Point) =>
Image
.circle(point.r * 0.125 + 7)
.fillColor(Color.red.spin(point.angle / -4.0))
.noStroke
val image = drawCurve(20, marker, parametricSpiral)