Your assignment is to write a java applet that makes some sort of interactively animated person, creature, machine, dancing tree, hopping vehicle, or whatever. The only rules are:
You should callvoid initFrame(); void push(); void pop(); void translate(double x,double y,double z); void rotateX(double theta); void rotateY(double theta); void rotateZ(double theta); void scale(double x,double y,double z); void transform(double src[], double dst[])
km.initFrame()
at the start of every frame.
This is the method that
resets the kinematic machine's internal matrix stack
S[]
to contain just a single identity matrix,
so that
sp=0
and
S[sp].identity()
.
Then you call the other routines
in any sequence you want, with the
the caveat that calls to
km.push()
and
km.pop()
must occur in matching pairs
(like the rules for parentheses).
Remember that the translate, rotate and scale
methods operate only on the top item
in the matrix stack
S[sp]
.
The
km.push()
method
duplicates the top entry in the stack,
thereby making the stack grow.
The
km.pop()
method
just decrements the stack pointer.
When you implement
km.push()
and
km.pop()
,
be sure to put in code that
checks for stack overflow and underflow errors.
The method
km.transform(src,dst)
allows you to query the kinematic machine
so that you can draw things.
For example, if you want to draw the square:
you might end up callingdouble A[][] = {{0,0,0},{.1,0,0},{.1,.1,0},{0,.1,0}};
where you might, for example, implement drawPolygon() as in the code that follows.drawPolygon(double A);
Below is a really simple example of an applet that uses the API that I described above. It just draws two cubes, an inner cube spinning inside an outer cube. Don't hand this in as your homework, but go ahead and use it for reference:
import java.awt.*; public class testKM extends GenericApplet { int width, height, x = 100, y = 100; KM km = new KM(); // ALLOCATE THE KINEMATIC MACHINE // DEFINE 8 VERTICES AND 6 FACES OF A CUBE double aaa[] = {-1,-1,-1}, baa[] = { 1,-1,-1}, aba[] = {-1, 1,-1}, bba[] = { 1, 1,-1}, aab[] = {-1,-1, 1}, bab[] = { 1,-1, 1}, abb[] = {-1, 1, 1}, bbb[] = { 1, 1, 1}; double a[][][] = { { aaa, baa, bba, aba }, { aab, bab, bbb, abb }, { aaa, aba, abb, aab }, { baa, bba, bbb, bab }, { aaa, baa, bab, aab }, { aba, bba, bbb, abb }, }; double L[][] = new double[100][3]; int count = 0; public void render(Graphics g) { if (width == 0) { width = bounds().width; height = bounds().height; } if (damage) { g.setColor(Color.white); g.fillRect(0, 0, width, height); g.setColor(Color.black); km.initFrame(); // INIT FRAME km.scale(.2,.2,.2); km.rotateY(.1 * x); // RESPOND TO MOUSE km.rotateX(.1 * y); // DRAW THE OUTER CUBE for (int n = 0 ; n < a.length; n++) drawPolygon(g, a[n]); km.scale(.5,.5,.5); // SCALE DOWN km.rotateX(.11 * count); km.rotateY(.12 * count); // SPIN km.rotateZ(.13 * count); // DRAW THE INNER CUBE for (int n = 0 ; n < a.length; n++) drawPolygon(g, a[n]); count++; } } void drawPolygon(Graphics g, double A[][]) { // DECLARE A TEMPORARY ARRAY double B[][] = new double[A.length][3]; // TRANSFORM ALL VERTICES OF POLYGON INTO TEMPORARY ARRAY for (int i = 0 ; i < A.length ; i++) km.transform(A[i], B[i]); // DRAW LINES BETWEEN SUCCESSIVE TRANSFORMED VERTICES for (int i = 0 ; i < A.length ; i++) { int j = (i + 1) % A.length; g.drawLine(viewportX(B[i]),viewportY(B[i]), viewportX(B[j]),viewportY(B[j])); } } double F = 3.5; // FOCAL LENGTH int viewportX(double V[]) { // HERE'S WHERE YOU MIGHT IMPLEMENT PERSPECTIVE return (int)(width/2 + V[0] * width); } int viewportY(double V[]) { // HERE'S WHERE YOU MIGHT IMPLEMENT PERSPECTIVE return (int)(height/2 - V[1] * width); } public boolean mouseDown(Event e, int x, int y) { moveXY(x, y); return true; } public boolean mouseDrag(Event e, int x, int y) { moveXY(x, y); return true; } void moveXY(int x, int y) { this.x = x; this.y = y; damage = true; } }