Computables of Architectural Design: Chapter
9
For Internal UVa. Use Only: Funded by a Teaching and Technology Initiative Grant 1996 - 97 Draft: January 15, 1997 Copyright © 1997 by Earl Mark, University of Virginia, all rights reserved. Disclaimer |
Recursion and Fractals
This chapter will examine the programming technique of recursion and the related description of fractal geometry. We will first explore simple two dimensional geometries. We will then explore three dimensional fractal shapes as might describe a mountain terrain, and other more architectural shapes.
Recursive Programming
A recursive procedure in the simplest sense is a program that calls itself a number of times to perform parts of a task in which it is engaged. Each call of a procedure to itself might change the value of certain parameters thereby generating some progressive change in what is done. For example, a recursive procedure might describe a square that rotates inwardly at decreasing proportions. The first call of the procedure draws the outer most square. The next call of the procedure (the first time the procedure calls itself) results in the first inwardly shrinking and rotated square, as in the image of the rotating squares below. Each inner square within the progression below is determined at five sixth's times the length of the preceding outer square. There are a total of 8 squares. Correspondingly, the recursive procedure is called is 8 times to perform the drawing of the square rotated at shrinking proportions. The first call of the recursive sub procedure is from the sub main procedure. The recursive sub procedure then calls itself the remaining 7 times.
![]() |
The effect of the program is similar to a problem for drawing a series of rotating squares that had been presented in the homework for chapter 3. The program of chapter 3 created a series of inwardly rotating squares, where each new square was sized at two thirds the size of the preceding outer square. That earlier program was written using an iterative loop.This new program, however, performs a similar task but using the technique of recursion. The program that performs the recursive drawing is presented below.
Note that the program as a whole is organized in a now familiar way with sub procedures. There is a sub procedure drawsq to draw a square of four sides (or any closed polygon of four sides) from four points. There is also a sub procedure f56pt which finds a point located at a five sixths of the distance from a first point point1 to a second point point2. These two sub procedures are straightforward and are like those we have reviewed in previous chapters. However, the sub procedure drawr56s is different than the sub procedures that we have examined before, and is at the core of the recursive process. In particular, it is a procedure that calls itself.
The recursive process of drawr56s is focused on two conditions.
1). The first condition is where the value of the parameter recur is greater than 1 (i.e., recur > 1). In this case the procedure drawr56s will:
- draw a square as determined by the points point1, point2, point3, and point4
- calculate the points of the next inwardly rotated square
- decrease the value of the parameter recur by one
- call itself drawr56s to draw the next inwardly rotated square
2). The second condition is where the value of the parameter recur is equal to the numerical value 1 (i.e., recur = 1). In this case the procedure drawr56s will only
- draw a square as determined by the points point1, point2, point3, and point4
If this second condition is true, then the procedure does not call itself again. This is the grounding condition for this recursive procedure, when the recursion itself (the process of the sub procedure calling itself) comes to a halt.
In describing this recursive procedure, we would identify the recursive condition as being determined by the value of the parameter recur. Recursive procedures typically have a recursive condition. The recursion is typically concluded with a grounding condition (e.g., recur = 1).
Note that if the value of the input parameter recur is 8, then the procedure drawr56s will be called 1 time by the sub main procedure, and that it will be called 7 times by the procedure drawr56s itself. In effect, the value of the variable recur is the key to the number of recursions. The value of recur is reduced with each recursive call, leaving one fewer recursion left to perform each new time drawr56s is called.
The handling of the input parameters to drawr56s are important to clarify with respect to the recursive process. All parameters are passed by reference. However, the first four parameters point1, point2, point3 and point4 are managed in a slightly different way than the parameter recur. Lets analyze them separately in the following table:
Parameters | How Passed | Analysis |
point1 point2 point3 point4 |
by reference | With each recursive call, a new variable mpoint1 is created within the procedure drawr56s. It is passed in the next call to from drawr56s to itself through the parameter point1. Since the procedure is called recursively seven times in this example, seven different versions of the variable mpoint1 would be created. The same holds true for parameters mpoint2, mpoint3, mpoint4, and for point2, point3 and point4 respectively. |
recur | by reference | With each recursive call, the variable recur is also passed by reference. In each case, the passed value of the parameter recur has been decremented by 1. The program reaches the grounding condition when the value of recur has been decreased to 1. The parameter recur is passed without going through an intermediate variable. |
Note that recursive programming can require some sophistication in the allocation of memory for variables. This is a topic that we have avoided here. Our program is simple, but not necessarily well written for conserving memory allocation. The iteration technique discussed in chapter 3 would be much preferred with respect to conserving memory. With iteration, we re-use the same memory for variables that are re-assigned new values every time a loop is revisited.. With recursion, however, we are allocating additional memory for the re-use of the same variables in the recursive call. A recursive program that uses the memory management methods shown here will quickly run out it (i.e., it will run out of so-called stack space. a particular allocation of memory). Memory allocation and recursion is a topic, however, that we will bypass now for the sake of keeping the present introduction to recursive programming simple.
All recursive procedures could be rewritten with greater memory efficiency as iterative procedures. However, sometimes recursion becomes a convenient way to express certain phenomenon. We will now see an example of this with the following fractal program that draws a series of triangles recursively.
A Recursively Created Fractal
Fractal graphics have the property that the shape of its parts are self-similar to the whole. The following two illustrations of triangles, Fractal Image One and Fractal Image Two, show progressively developed examples of the same fractal. That is, the second image is a more recursive version of the first image. To understand how this is so, imagine that the first image consists of a triangle that contains three smaller triangles at each of its three corners. Lets refer to each of these smaller triangles by the letter A. There is also a fourth triangle at the center of this figure. Lets refer to this triangle at the center by the letter B. Triangle B is created as a side effect only of drawing the other three triangles A. Now imagine that we repeat the entire composition of Fractal Image One in each of its three corner triangles A. This would result in the composition of triangles at the right. Note that the fourth triangle B at the center of this figure is not changed. The second image recreates the pattern of the first image as if it reproduced a self-similar version itself in each of its three smaller triangles A.
![]() |
![]() |
Fractal Image One |
Fractal Image Two |
Now lets take the recursion of this pattern two steps further. Within each step, we take each of the smaller triangles A only and we repeat the entire composition of Fractal Image One inside of them. Within each step, we also do not modify the composition of Triangle B.
![]() |
![]() |
Fractal Image Three |
Fractal Image Four |
As the fractal composition progressively changes onto images five and six, the density of the triangles increase. We can still see the self-similarity of the parts of each of the progressive images to the beginning pattern.
![]() |
![]() |
Fractal Image Five |
Fractal Image Six |
It should be obvious from the study of the above images that if we were to zoom up on any part of Fractal Image Six, we would find that it contains a replication in miniature of the original composition of Fractal Image One. In the image below on the left there is a mark on an area with a red box. In the image on the right, we are given a close-up view of that red area.
![]() |
![]() |
Fractal Image Six With Marked Area |
Fractal Image Six Close-Up of Marked Area |
The program that generates these fractal images makes use of a recursive technique. It contains two procedures drawtri and midpt that are not unlike the geometry procedures we have examined in previous chapters. Examination of these procedures is left to the reader. It also contains a recursive procedure drawrtri that uses a parameter recur which serves as the key to the recursive condition. This program is given below.
3D Fractal of Pyramid Through 6 Recursions
A review of the program itself reveals a logic that is very similar to the previous example of 2D triangles. The program is listed below. The sub procedures Pyramid, PpyramidPts and DrawPyramid should be easy to interpret based on the comment lines embedded within them. The main work of the program is done with the recursive sub procedure DrawrPyramid. Note that it contains a main conditional statement. Within the conditional statement, if recur = 1, then we are at the grounding condition, and a single pyramid is generated. Otherwise, if recur > 1, then five recursive procedure calls to DrawrPyramid are invoked. These five recursive procedure calls generate four recursively created pyramids in the lower four corners and one recursively created pyramid at the apex of the initial pyramid.
Mountain Fractal
A similar 3d fractal is that of a mountain terrain which is based on pyramid like elements. Unlike the previous program, the pyramids of the mountain fractal have a base of three points rather than a base of four points. A random number generator controls the size of various peaks. The range of random numbers can be modified such that your get either wider or narrower peak sizes. If the recursive procedure is run only once, then the value of a parameter recur = 1 (see program below) and only the grounding condition is ever realized. If only the grounding condition is realized, then a base pyramid only is generated (fractal 1 below). If the recursive procedure is run recursively for 1 time, then the value of a parameter recur = 2 and the recursive condition is realized once. If the recursive condition is realized once, then three pyramids are generated in sequence (fractal 2a, fractal 2b and fractal 2c) on what would be the faces of the base pyramid. We have the following situations described in the table of images below.
![]() |
![]() |
fractal 1 - base pyramid |
fractal 2a - front pyramid |
![]() |
![]() |
fractal
2b - front & back right pyramids |
fractal 2c - front, back
left & right pyramids |
Note that in case of 2 recursions, the base pyramid (fractal 1) is not actually drawn, but its vertices are calculated only as a basis for generating the remaining pyramids (fractal 2a, fractal 2b and fractal 2c). The pyramids of fractal 2a, fractal 2b and fractal 2c are like the "skin" of the base pyramid of fractal 1. They are like a "skin" in that they cover the faces of the base pyramid completely. Therefore, in the case of 2 recursions, it is really not necessary to draw the base pyramid, but only to calculate its vertices so as to determine the drawings of pyramids represented in fractal 2a, fractal 2b and fractal 2c. Similarly, for any number of recursions, the program draws the outer most "skin" of pyramids and it calculates only the other pyramids upon which the outer most "skin" of pyramids are based. Even if the the other "base" pyramids were fully drawn, only the outer "skin" of pyramids would be visible. Therefore, for the sake of conserving the drawing size, the outer "skin" is the only part of the fractal actually drawn.
The program for this mountain fractal appears below. Many of the sub procedures used to generate the fractal mountain are similar to those that we have reviewed in earlier examples. In particular, the methods of the sub procedures drawTri, drawPyramid, copypoint, getmaxdist, pointDist, and getmaxnum should be self-evident from the comment lines already included within the program. The procedure drawrMtn operates recursively in the same way as the procedures drawr56s and DrawrPyramid which were reviewed in earlier examples presented in this chapter. Of all the sub procedures that are contained in the program, the sub procedures getbase and getranApex are substantively different that what has been examined before. First review the entire program, and then the procedures getbase and getranApex will be described in some greater detail.
The sub procedure getbase requests that the user input three points. These three points are used to determine the base of the first base pyramid. In the case where recur > 1, the first base pyramid is not drawn, but is used to calculate the basis of the outer "skin" of pyramids. Note that getbase makes us of a number of system supplied object variables to prompt for input, check on the input received, and return the input to the appropriate MbePoint variables (e.g., point1, point2, and point3). The sequence of steps for retrieving a data point from the user in the sub procedure getbase is to:
The methods of 1 through 4 are generally used to get data points from the user, and may apply to a number of other programs. The role of the different system supplied object variables and their components is suggested by the comment lines embedded in the getbase procedure. This method can be easily copied for other interactive programs where user input of point data is needed. This explanation may suffice for the being able to adapt the getbase procedure for other situations. For more detailed information on these object variables, the reader is referred to the the Microstation 95' Basic Guide.
The sub procedure getranApex relies upon the use of a random number generator. Note that this random number generator is first invoked in the main procedure with the statement:
' initialize the random number generator Randomize |
The invocation of the random number generator in the sub procedure main ensures that the random function statement in the sub procedure getranApex excerpted below will generate a random number from 0 to maxheight. This random number is assigned to the variable height. The variable height in turn is used to determine the apex of each pyramid.
height = Random (0, maxheight) |
Note that such a random number height may greatly exceed in size the dimensions of the its own base. This would be a problem if it causes the resulting form to appear like a tall and narrow triangular spire. That is, such a tall and narrow form would be unsuited to the representation of a mountain intended here. Therefore, some additional checks on the height of each pyramid are placed in the program. In particular the following statement ensures that the height of the apex on a pyramid never exceeds in size the maximum distance that exists between the points in the base of the pyramid.
' determine the maximum distance between the points in the base of the pyramid call getmaxdist (point1, point2, point3, maxdist) if maxdist < maxheight then maxheight = maxdist end if |
If the fractal mountain program is run for an increasing number of recursions (i.e., the value of recur is 6 or 7 or 8), then the peaks within the mountain become more numerous and dense. For the a following image, the assignment of the value recur = 8 is used in the sub procedure main, and a texture map is applied to the resulting fractal pyramids. The image below is a close-up of the large mountain fractal which is formed.
![]() |
fractal mountain for recur = 8
Summary
Within this chapter, we have explored the use of recursive procedures A recursive procedures is one that calls itself in order to complete a task in which it is engaged. It typically ends when it encounters a grounding condition where the value of some variable reaches a limit (e.g., recur = 1). A recursive procedure continues to invoke itself when it encounters a recursive condition where the value of some variable has not yet reached a limit (e.g., recur > 1).
A recursive program was used to generate the rotating squares of the first example. The same graphic composition might alternatively have been created using an iterative program as we had seen in chapter 3. The recursive program style, however, seems to express most directly the self-similar nature of fractal graphics. That is, a program that calls itself is like a fractal that has parts that resemble its overall composition. Still, all of the recursive programs of this chapter might have been rewritten with even greater efficiency with the use of iterative loops. This is an exercise that could be explored by the reader using the iterative techniques described in chapter 3.
The fractal programs we have seen were very similar in their use of the variable recur to control the progression towards grounding condition. We have observed that that the recursive sub procedure drawrPyramid of the program that draws the fractal pyramids is similar in structure to the recursive sub procedure drawrtri of the program that draws the 2d fractal triangles. In turn, we have also observed that the recursive sub procedure drawrMtn of the program that draws the 3D mountain fractal is similar in structure to the recursive sub procedure drawrPyramid of the program that draws the 3D pyramid fractal. This structure can be applied to recursively drawn cubes as in the assignment below and other such kinds of graphic compositions. However, in the next chapter we will also look at alternative approaches to generating fractal images where the property of self-similarity holds, but where the other means than a variable like recur drive the graphics construction process.
Assignment 8: Fractals and Final Assignment