// Implement a Kinematic Virtual Machine
import java.util.*;
public abstract class KVM extends Vector // Kinematic Virtual Machine Object
{
// Drawing routines must be implemented externally by an extended class
public abstract void drawLine(double x1, double y1, double x2, double y2);
public abstract void drawJoint(String name, double x, double y);
KVM() { // Constructor
for (int i = 0 ; i < m.length ; i++) // Build the Stack
m[i] = new Matrix3D();
}
//Names in CAPS are constants defined in class KVI below
public void lineTo(double x,double y,double z) {
matrix(add(KVI.LINETO)).translate(x,y,z);
}
public void moveTo(double x,double y,double z) {
matrix(add(KVI.JOINT)).translate(x,y,z);
}
//adds a JOINT to the stack and sets its name
public void joint(String name) { instr(add(KVI.JOINT)).name = name; }
public void pop() { add(KVI.POP); }
public void push() { add(KVI.PUSH); }
public Matrix3D matrix(int i){ return instr(i).matrix; } // Get Instr Matrix
public String name(int i) { return instr(i).name; } // Get Instr Name
//instr() returns the KVI object at a certain position. It can then be used as a normal KVI object
private KVI instr(int i) { return (KVI)elementAt(i); }// Get Instruction
private int add(int type){ // Add Instruction
addElement(new KVI(type));
return size()-1;
}
private Matrix3D[] m = new Matrix3D[20]; // The Matrix Stack
// Render the Scene
public void render() {
int n = 1, type;
m[0].identity();
//loops through all the instructions
for (int i = 0 ; i < size() ; i++)
if ((type = instr(i).type) == KVI.LINETO) { // Draw a Line
double x = m[n-1].get(0,3); // From Local
double y = m[n-1].get(1,3); // Origin to
m[n-1].postMultiply(matrix(i)); // Transformed
drawLine(x, y, m[n-1].get(0,3), m[n-1].get(1,3)); // Local Origin
}
else if (type == KVI.JOINT) { // Transform
drawJoint(name(i), m[n-1].get(0,3), m[n-1].get(1,3));
m[n-1].postMultiply(matrix(i));
}
//PUSH and POP keep track of which coordinate system the
//virtual machine is in. At the highest level, it is absolute screen
//coordinates. Then it progresses by the LOCAL tags to the legs,
//the arms, the head and so on
else if (type == KVI.PUSH) // PUSH
m[n++].set(m[n-2]);
else // POP
n--;
}
}
// One Kinematic Instruction Object
class KVI
{
static final int LINETO = 0;
static final int JOINT = 1;
static final int POP = 2;
static final int PUSH = 3;
int type;
String name = null;
Matrix3D matrix = new Matrix3D();
KVI(int type) { this.type = type; }
}