MathClass Lesson 1:
Blocks and Bricks
Section 3: Building a Block Factory
Creating Maple Procedures
If we are to construct more complex figures out of cubes and manipulate them in more interesting ways we need a more efficient means of producing the rectangular boxes with which to build them. It would be nice if there were a Maple word which instructed the program to make, say, a cube of side 1 and place it at a location of our choice. In the previous chapter we did all of the work that such a word would do. We constructed the basic cube and placed it in the desired location by specifying a "shift". The steps to create a simple, colorless cube might be:
> restart:
>
front:=[v1,v2,v3,v4]:
back:=[v5,v6,v7,v8]:
left:=[v4,v8,v5,v1]:
right:=[v3,v2,v6,v7]:
bottom:=[v3,v4,v8,v7]:
top:=[v1,v2,v6,v5]:
box:=[front,back,left,right,top,bottom]:
> shift:=[0,0,0]:
> v1:=[0,0,0]+shift: v2:=[1,0,0]+shift: v3:= [1,1,0]+shift: v4:=[0,1,0]+shift: v5:=[0,0,1]+shift: v6:=[1,0,1]+shift: v7:=[1,1,1]+shift: v8:=[0,1,1]+shift:
>
cube0:= plots[polygonplot3d](box):
cube0;
If we wanted the cube placed at any particular place in space all we have to do is change the value of "shift". If we wanted to retain the previous cube then instead of simply having plots[polygonplot3d] immediately draw the picture we assigned the plot structucture generated to a word, say "cube1". Then we could change the shift and the name, say to "cube2" and have plots[display] show us our cubes separately or individually as we wish.
What we would really like to do is have a Maple word, say "cube" which would take in the shift and produce the plot structure for the corresponding cube. We want the command "cube([0,0,0])" to produce the results of the previous set of commands and would want "cube([0,0,1])" to produce the results of simply changing "shift" to "[0,0,1]" in the
same list of commands. That is, all we want is a way to vary the value of "shift " in this set of commands. Maple does this with
procedures
. The form of a Maple procedure is simple:
ProcedureName:= proc(input_variable)
Maple commands in which "input_variable" is treated as input.
end;
For instance suppose we want a Maple word which always returns a picture of a unit square of whichever color we specify. We need a choice for this word, the ProcedureName. Any choice will work provided its not "reserved" by Maple. For instance we might choose "colorsquare". We need a name for the procedure variable. Since we are going to vary color we choose something like "clr" since we have seen that "color" is a word already defined in Maple. Finally we need to know the Maple word which will produce a square of a given color. We know that the following will work
:
plots[polygonplot3d]([[0,0,0],[1,0,0],[1,1,0],[0,1,0]], color=red);
Thus following the above format we create a new word:
>
colorsquare:=proc(clr)
plots[polygonplot3d]([[0,0,0],[1,0,0],[1,1,0],[0,1,0]], color=clr);
end:
We can test the work out right away.
> colorsquare(blue);
Creating our "cube" word is no more difficult and is done essentially by cutting and pasting the code that does one general enough case, changing the specific values in the code to the variable quantities for the procedure and "wrapping" this in the "proc()...end wrapper". Doing this with the instructions that made "cube0" whe would assemble
cube:=proc(shift)
"instructions for making cube 0"
end;
>
cube:=proc(shift)
local v1, v2, v3, v4, v5, v6, v7, v8, front, back, left, right, bottom, top, box;
v1:=[0,0,0]+shift:
v2:=[1,0,0]+shift:
v3:= [1,1,0]+shift:
v4:=[0,1,0]+shift:
v5:=[0,0,1]+shift:
v6:=[1,0,1]+shift:
v7:=[1,1,1]+shift:
v8:=[0,1,1]+shift:
front:=[v1,v2,v3,v4]:
back:=[v5,v6,v7,v8]:
left:=[v4,v8,v5,v1]:
right:=[v3,v2,v6,v7]:
bottom:=[v3,v4,v8,v7]:
top:=[v1,v2,v6,v5]:
box:=[front,back,left,right,top,bottom]:
plots[polygonplot3d](box);
end:
For the moment pay no attention to the "warning" messages, we will clean that up shortly. Right now what we need to see is that we do indeed have a "cube" word. The idea is always to get something working and improve it.
>
joe:=cube([1,2,4]): sam:=cube([1,0,1]): sally:=cube([1,1,1]): joesamsally:=plots[display]([joe,sam,sally],color=red,scaling=constrained):
joesamsally;
Now that we have a basic version of "cube" we can add features. Suppose we want to specify the style and color of the cube as well as the shift. This is easy as Maple procedures are not restricted to a single variable. It is a good idea to make a single improvement at a time, though. This makes finding errors much easier. Lets specify the style first. All we need to do is copy the code over. We don't go back and change our only copy of a piece of working code . We copy the working version, paste it in and (ususally) change the name at least temporarily.
>
tempcube := proc (shift)
local v1, v2, v3, v4, v5, v6, v7, v8, front, back, left, right, bottom, top, box;
v1 := [0, 0, 0]+shift;
v2 := [1, 0, 0]+shift;
v3 := [1, 1, 0]+shift;
v4 := [0, 1, 0]+shift;
v5 := [0, 0, 1]+shift;
v6 := [1, 0, 1]+shift;
v7 := [1, 1, 1]+shift;
v8 := [0, 1, 1]+shift;
front := [v1, v2, v3, v4];
back := [v5, v6, v7, v8];
left := [v4, v8, v5, v1];
right := [v3, v2, v6, v7];
bottom := [v3, v4, v8, v7];
top := [v1, v2, v6, v5];
box := [front, back, left, right, top, bottom];
plots[polygonplot3d](box);
end:
This is, of course simply our original code with a different name. Now we modify it to take both a shift and a color. We have indicated the changes in upper case in the following copy. In this case we simply add a variable "clr" and the option color=clr in the plots[polygonplot3d] command.
>
tempcube1 := proc (shift, clr)
local v1, v2, v3, v4, v5, v6, v7, v8, front, back, left, right, bottom, top, box;
v1 := [0, 0, 0]+shift;
v2 := [1, 0, 0]+shift;
v3 := [1, 1, 0]+shift;
v4 := [0, 1, 0]+shift;
v5 := [0, 0, 1]+shift;
v6 := [1, 0, 1]+shift;
v7 := [1, 1, 1]+shift;
v8 := [0, 1, 1]+shift;
front := [v1, v2, v3, v4];
back := [v5, v6, v7, v8];
left := [v4, v8, v5, v1];
right := [v3, v2, v6, v7];
bottom := [v3, v4, v8, v7];
top := [v1, v2, v6, v5];
box := [front, back, left, right, top, bottom];
plots[polygonplot3d](box,color=clr)
end:
Now test this change right away.
> tempcube1([0,0,0],red);
Now we can go another step and change the style
>
tempcube2 := proc (shift,clr,styl)
local v1, v2, v3, v4, v5, v6, v7, v8, front, back, left, right, bottom, top, box;
v1 := [0, 0, 0]+shift;
v2 := [1, 0, 0]+shift;
v3 := [1, 1, 0]+shift;
v4 := [0, 1, 0]+shift;
v5 := [0, 0, 1]+shift;
v6 := [1, 0, 1]+shift;
v7 := [1, 1, 1]+shift;
v8 := [0, 1, 1]+shift;
front := [v1, v2, v3, v4];
back := [v5, v6, v7, v8];
left := [v4, v8, v5, v1];
right := [v3, v2, v6, v7];
bottom := [v3, v4, v8, v7];
top := [v1, v2, v6, v5];
box := [front, back, left, right, top, bottom];
plots[polygonplot3d](box,color=clr,style=styl )
end:
> tempcube2([2,1,3], blue, patch);
Now we can play with colored cubes:
>
cube1:=tempcube2([0,0,0],blue,patch):
cube2:=tempcube2([1,0,0],yellow ,patch): cube3:=tempcube2([2,0,0],tan ,patch):cube4:=tempcube2([1/2,0,1],green ,patch):cube5:=tempcube2([3/2,0,1],red ,patch):cube6:=tempcube2([1,0,2],red,patch):
>
sixcubes:=plots[display]([cube1,cube2,cube3, cube4,cube5,cube6 ],scaling=constrained):
sixcubes;
Another Example of how to "procedurize" a sequence of commands.
It is very important to learn the process of organizing sequences of Maple commands which solve a specific problem into a procedure for doing a general problem of that form. For example. The following command sequence calculates the equation of the line though the two points [1,3] and [-5,12] .
>
eqn:= y=slope*x+yintercept;
>
slope:= (12 - 3)/(-5 - 1);
>
yintercept:=3 - slope*1;
> eqn;
We want to modify this to take in the x and y coordinates of any two points [x1,y1] and [x2,y2] and to return the equation of the line through them. Once we see that we should think of [1,3] as the particular [x1,y1] and [-5,12] as the particular [x2,y2] we can readily wrap this into a procedure with a name such as "lineequ". Note that we are ignoring for the moment the possibility that x1=x2 in which case Maple will complain about division by zero. We'll learn to take care of such things later
.
>
lineequ:=proc(x1,y1,x2,y2)
local slope, intercept, eqn;
eqn:= y=slope*x+intercept;
slope:= (y2 - y1)/(x2 - x1);
intercept:= y1 - slope*x1;
y=slope*x+intercept;
end:
>
> lineequ( 1,3, -5,12);
>
> L1:=y=3*x-2;
> L2:=y=7*x-5;
> ans:=solve({L1,L2},{x,y});
>
> subs(ans,[x,y]);
>
> sum(i^2,i=1..4781);
>
Example:
One often finds colored cubes as children's toys and these often have letters painted on them. Lets investigate the possibility of making a white cube with a blue "K" on one face. The white cube is no problem. We need to make the "K". We only know how to make CONVEX polygons so we must assemble our "K" from components of that type.
This one is made of the polygons A,B, and C. All we need to do is draw something like this on a piece of graph paper, read off the coordinates of the vertices, make up each of the polygons and put them together.
> A:=[[1/10,0,1/10],[1/10,0,9/10],[3/10,0,9/10],[3/10,0,1/10]];
>
> B:=[[3/10,0,4/10],[3/10,0,6/10],[6/10,0,9/10],[9/10,0,9/10]];
> C:=[[4/10,0,5/10],[6/10,0,6/10],[9/10,0,1/10],[7/10,0,1/10]];
>
K:=plots[polygonplot3d]([A,B,C],color=blue,style=patch):
whitecube:=tempcube2([0,0,0],white,patch);
>
Kcube:=plots[display]([K,whitecube]):
Kcube;
I t may be necessary to rotate the cube (use the mouse) in order to see the "K".
There are two problems here. The first is a very sloppy "K" which results from inaccurate reading of coordinates from a hastily drawn graph. This can be partially addressed by more careful graphing. The second problem is that some views of the cube show a two-toned "K". This is what happens when two patch-style pictures are in contact. Polygons are made of colored triangles and the computer is not able to resolve which is "above" the other. The solution is to move them slightly apart. In this case its we might have the "K" as being slightly raised above the surface of the cube. That just means altering the definition of K
> A:=[[1/10,-.01,1/10],[1/10,-.01,9/10],[3/10,-.01,9/10],[3/10,-.01,1/10]];
> B:=[[3/10,-.01,4/10],[3/10,-.01,6/10],[6/10,-.01,9/10],[9/10,-.01,9/10]];
> C:=[[4/10,-.01,5/10],[6/10,-.01,6/10],[9/10,-.01,1/10],[7/10,-.01,1/10]];
>
K:=plots[polygonplot3d]([A,B,C],color=blue,style=patch):
whitecube:=tempcube2([0,0,0],white,patch);
>
Kcube:=plots[display]([K,whitecube]):
Kcube;
This solves the
Lets add a red "K" to the other side
> A1:=[[1/10,1.01,1/10],[1/10,1.01,9/10],[3/10,1.01,9/10],[3/10,1.01,1/10]];
> B1:=[[3/10,1.01,4/10],[3/10,1.01,6/10],[6/10,1.01,9/10],[9/10,1.01,9/10]];
> C1:=[[4/10,1.01,5/10],[6/10,1.01,6/10],[9/10,1.01,1/10],[7/10,1.01,1/10]];
>
K1:=plots[polygonplot3d]([A1,B1,C1],color=red,style=patch):
> plots[display]([K,whitecube,K1]);
>
>
>
>
>
EXERCISE
: Change the "Kcube" so that there is a "K" on each face.
EXERCISE
: Make a yellow block with one the letters A,B,C,D,E,F on each face
.
EXERCISE
: Give each of the letters in the previous problem a different color.
EXERCISE
: Make the block in the previous problem appear to be made of a transparent material with the colored letters painted on its faees.
EXERCISE
: Make a stack of alphabet blocks that present your initials.