|
|
| Motto: Never open a spaceman's helmet on an uncharted planet. |
|
Here's cubes.html:
<html>
<head>
<title>Some cubes</title>
</head>
<body>
<applet code="Cube.class"
width=400
height=400>
</applet>
</body>
</html>
The approach now is top-down since we want
So, here's Cube.java:
import java.awt.*;
import java.net.*;
import java.io.*;
/*************************************************************
* A rotating cubes applet. See Chapter 11 of the BAJGP.
*
* Putting the classes to work with a quick and dirty applet.
*************************************************************/
public class Cube extends fNoFlickerApplet implements Runnable {
fGenericCamera camera;
fPoint3d camPos;
fAngle3d camAngle;
fPolyhedron cube;
fPolyhedronInstance cubeInstance[];
fPoint3d pos[];
fAngle3d agl;
Thread myThread;
public void init() {
//-- create a camera
camera=new fGenericCamera(400,400,Math.PI/2);
camPos=new fPoint3d(0,0,5);
camAngle=new fAngle3d();
//-- load a model from the file cube.f3d
try{
InputStream is=new URL(getCodeBase(),"cube.f3d").openStream();
cube=new fConvexPolyhedron(is);
} catch(Exception e) {
e.printStackTrace();
}
//-- create 9 instances of the cube
cubeInstance=new fPolyhedronInstance[9];
for(int n=0; n<9; n++) {
cubeInstance[n]=new fPolyhedronInstance(cube);
}
//-- create the positions and angle
pos=new fPoint3d[9];
int n=0;
for(int y=-5; y<=5; y+=5){
for(int x=-5; x<=5; x+=5){
pos[n]=new fPoint3d(x,y,0);
n++;
}
}
agl=new fAngle3d();
//-- start the thread
myThread=new Thread(this);
myThread.start();
}
public void run() {
while(true) {
//-- sleep 1/10 of a second
try {
myThread.sleep(100);
} catch ( InterruptedException e) {
// nothing
}
//-- update the angle of the models
agl.x+=Math.PI/20; agl.y+=Math.PI/30;
//-- update camera angle and position
camPos.z+=0.2; camAngle.z+=Math.PI/50;
camera.setOrientation(camPos,camAngle);
//-- request a repaint
repaint();
}
}
public void start() {
if(myThread==null) {
myThread=new Thread(this);
myThread.start();
}
}
public void stop() {
if(myThread!=null) {
myThread.stop();
myThread=null;
}
}
public void paint(Graphics g) {
//-- clear screen
g.clearRect(0,0,size().width,size().height);
//-- paint the models
for(int n=0; n<9; n++){
cubeInstance[n].setOrientation(pos[n],agl);
cubeInstance[n].paint(g,camera);
}
}
}
This requires the following (data) file, called cube.f3d:
It also requires the following classes:8 -1 1 1 -1 1 -1 1 1 -1 1 1 1 -1 -1 1 -1 -1 -1 1 -1 -1 1 -1 1 6 4 0 1 2 3 128 128 0 4 0 4 5 1 128 0 128 4 1 5 6 2 0 128 128 4 2 6 7 3 128 0 0 4 0 3 7 4 0 0 128 4 5 4 7 6 0 128 0
fNoFlickerApplet
fGenericCamera
fPoint3d
fAngle3d
fPolyhedron
fPolyhedronInstance
import java.awt.*;
import java.applet.*;
/**
* Represents a panel that does the painting offscreen
* which avoids flickering. Good for using in animations.
*/
class fNoFlickerApplet extends Applet {
private Image offScreenImage;
private Graphics offScreenGraphics;
private Dimension offScreenSize;
public final void update(Graphics theG){
Dimension d=size();
if((offScreenImage==null) ||
(d.width != offScreenSize.width) ||
(d.height != offScreenSize.height)) {
offScreenImage = createImage(d.width,d.height);
offScreenSize = d;
offScreenGraphics = offScreenImage.getGraphics();
offScreenGraphics.clearRect(0,0,offScreenSize.width,
offScreenSize.height);
}
paint(offScreenGraphics);
theG.drawImage(offScreenImage,0,0,null);
}
}
Now the generic camera.
/**
* A generic camera.
*/
public class fGenericCamera extends Object {
//-- a temporary buffer used for projection
protected static fArrayOf2dPoints our2dBuffer=
new fArrayOf2dPoints(new int[100],new int[100],100);
//-- a temporary buffer used for WCS to VCS transform
protected static fArrayOf3dPoints our3dBuffer=new fArrayOf3dPoints(100);
//-- the screen distance
protected double screendist;
//-- screen origo
protected int x0,y0;
//-- the viewangle
protected double myViewAngle;
//-- the matrix used for the WCS to VCS tranform
fMatrix3d myWCStoVCSmatrix;
//-- mark if the matrix is dirty
boolean matrixIsDirty;
//-- the position and angle of the camera in WCS
fPoint3d myPosition;
fAngle3d myAngle;
/**
* constructs a camera by specifing the widht, height and viewangle
*/
public fGenericCamera(int width,int height,double viewAngle){
myViewAngle=viewAngle;
//-- calculate the screen origo
x0=width>>1; y0=height>>1;
//-- calculate the screen distance
screendist=(double)x0/(Math.tan(viewAngle/2));
//-- construct the matrix
myWCStoVCSmatrix=new fMatrix3d();
//--
myPosition=new fPoint3d();
myAngle=new fAngle3d();
matrixIsDirty=true;
}
/**
* sets the position and angle of the camera.
*/
public void setOrientation(fPoint3d pos,fAngle3d agl){
if(myPosition.equals(pos)==false){
myPosition.set(pos);
matrixIsDirty=true;
}
if(myAngle.equals(agl)==false){
myAngle.set(agl);
matrixIsDirty=true;
}
}
/**
* projects an array of 3d points to the temporary 2d buffer
*/
public fArrayOf2dPoints project(fArrayOf3dPoints p3d){
//-- updates the matrix if it needed
updateMatrix();
//-- transform the WCS vertices to VCS storing the results
//-- in a buffer
myWCStoVCSmatrix.transform(p3d,our3dBuffer);
//-- project the VCS coordiantes to SCS storing the results
//-- in a buffer
for(int n=0;n<p3d.npoints;n++){
double z=our3dBuffer.z[n];
our2dBuffer.x[n]=-(int)(screendist*our3dBuffer.x[n]/z)+x0;
our2dBuffer.y[n]= (int)(screendist*our3dBuffer.y[n]/z)+y0;
}
//-- lend the buffer to the caller.
return our2dBuffer;
}
/**
* updates the matrix
*/
private void updateMatrix(){
if(matrixIsDirty==true){
//-- only remake the matrix if it is "dirty"
myWCStoVCSmatrix.makeWCStoVCStransform(myPosition,myAngle);
matrixIsDirty=false;
}
}
}
Here's the three dimensional point:
public class fPoint3d{
public double x;
public double y;
public double z;
public fPoint3d (double x0, double y0, double z0) {
x=x0; y=y0; z=z0;
}
public fPoint3d () {
x=y=z=0;
}
public fPoint3d (fPoint3d p1, fPoint3d p2) {
x=p2.x-p1.x; y=p2.y-p1.y; z=p2.z-p1.z;
}
public fPoint3d (fPoint3d p) {
x=p.x; y=p.y; z=p.z;
}
void vectorProduct (fPoint3d p1, fPoint3d p2) {
x=p1.y*p2.z-p1.z*p2.y;
y=p1.z*p2.x-p1.x*p2.z;
z=p1.x*p2.y-p1.y*p2.x;
}
void normalize (double length) {
double t=length/Math.sqrt(x*x+y*y+z*z);
x=t*x; y=t*y; z=t*z;
}
void plus (fPoint3d p) {
x+=p.x; y+=p.y; z+=p.z;
}
double dotProduct (fPoint3d p) {
return p.x*x+p.y*y+p.z*z;
}
boolean equals (fPoint3d p) {
return (p.x==x)&&(p.y==y)&&(p.z==z);
}
void set (fPoint3d p) {
x=p.x; y=p.y; z=p.z;
}
void times (double s) {
x*=s; y*=s; z*=s;
}
void negate () {
x=-x; y=-y; z=-z;
}
public String toString () {
return new String("("+x+", "+y+", "+z+")");
}
}
Here are the polyhedron classes, starting with the abstract
Polyhedron class:
/*************************************
polyhedronclasses.java
*************************************/
import java.awt.*;
import java.io.*;
/**
* A polyhedron class that is made out of a list of vertices
* and a list of indexing polygons.
*/
abstract class fPolyhedron extends Object {
//-- the 3d coordiantes for the model
protected fArrayOf3dPoints myVertices;
//-- the polygons
protected fIndexingPolygon myPolygons[];
protected int nbrPolygons;
/**
* construct a polyhedron with the supplied data.
*/
protected fPolyhedron(fArrayOf3dPoints points,fIndexingPolygon polys[],int npolys){
myVertices=points;
myPolygons=polys;
nbrPolygons=npolys;
}
/**
* construct a polyhedron from a stream.
*/
public fPolyhedron(InputStream is) throws IOException {
fromString(is);
}
/**
* paint the polyhedron using the supplied 2d coordiantes.
*/
public abstract void paint(Graphics g,fArrayOf2dPoints point2d);
/**
* make a string representation of this polyhedron
*/
public String toString(){
String str=new String();
//-- make the array of 3d points into a stream
str=myVertices.toString();
//-- write to stream how many polygons there are
str=str+nbrPolygons+"\n";
//-- write all polygons to the stream
for(int n=0;n<nbrPolygons;n++){
str=str+myPolygons[n].toString();
}
return str;
}
/**
* read the polyhedron from a stream
*/
public void fromString(InputStream is) throws IOException {
//-- make a stream tokenizer
StreamTokenizer stream = new StreamTokenizer (is);
stream.commentChar('#');
//-- get the points
myVertices=new fArrayOf3dPoints(is);
myVertices.toString();
//-- get the # polygons
stream.nextToken(); nbrPolygons=(int)stream.nval;
//-- create the vector
myPolygons=new fIndexingPolygon[nbrPolygons];
//-- read each polygon
for(int n=0;n<nbrPolygons;n++){
myPolygons[n]=new fFilledPolygon(is);
}
}
public fArrayOf3dPoints getVertices(){
return myVertices;
}
public abstract fPolyhedron makeClone();
public void scalePoints(double fx,double fy,double fz){
for(int n=0;n<myVertices.npoints;n++){
myVertices.x[n]*=fx; myVertices.y[n]*=fy; myVertices.z[n]*=fz;
}
}
}
class fConvexPolyhedron extends fPolyhedron {
/**
* construct a polyhedron with the supplied data.
*/
public fConvexPolyhedron(fArrayOf3dPoints points,fIndexingPolygon polys[],int npolys){
super(points,polys,npolys);
}
/**
* construct a polyhedron from a stream.
*/
public fConvexPolyhedron(InputStream is) throws IOException {
super(is);
}
/**
* overrides fPolyhedron.paint(..)
* the polygons don't need to be sorted.
*/
public void paint(Graphics g,fArrayOf2dPoints point2d){
//-- the polygons don't have to be sorted
for(int n=0;n<nbrPolygons;n++){
myPolygons[n].paint(g,point2d.x,point2d.y);
}
}
/**
* Makes a clone of this polyhedron.
*/
public fPolyhedron makeClone(){
fIndexingPolygon polys[];
polys=new fIndexingPolygon[nbrPolygons];
for(int n=0;n<nbrPolygons;n++){
polys[n]=myPolygons[n].makeClone();
}
return new fConvexPolyhedron(myVertices.makeClone(),polys,nbrPolygons);
}
}
Here's the polyhedron instance.
/***************************
fpolyhedroninstance.java
****************************/
import java.awt.*;
/**
* Class that represents an instance of a polyhedron.
*/
public class fPolyhedronInstance extends Object {
//-- the transformed vertices
protected fArrayOf3dPoints transformedVertices;
//-- the matrix used for transformations
protected fMatrix3d myTransformMatrix;
//-- the polyhedron
protected fPolyhedron thePolyhedron;
//-- position in WCS
protected fPoint3d myPosition;
//-- the angle in WCS
protected fAngle3d myAngle;
//--
protected boolean positionIsDirty,angleIsDirty;
/**
* construct an instance of the supplied polyhedron.
*/
public fPolyhedronInstance(fPolyhedron poly){
//-- the polyhedron that this instance is using
thePolyhedron=poly;
//-- create the vertices to be used for storing transformations
try{
transformedVertices=(fArrayOf3dPoints)thePolyhedron.getVertices().makeClone();
} catch(Exception e){e.printStackTrace();}
myPosition=new fPoint3d();
myAngle=new fAngle3d();
myTransformMatrix=new fMatrix3d();
}
/**
* set the position and angle for this polyhedron instance.
*/
public void setOrientation(fPoint3d pos,fAngle3d agl){
if(myPosition.equals(pos)==false){
//-- if position has changed then mark the matrix
//-- as "dirty" meaning that the transformed points
//-- need to be updated.
myPosition.set(pos);
positionIsDirty=true;
}
if(myAngle.equals(agl)==false){
myAngle.set(agl);
angleIsDirty=true;
}
}
/**
* paint the polyhedron instance.
*/
public void paint(Graphics g,fGenericCamera camera){
if(positionIsDirty || angleIsDirty){
//-- position or angle has changed and the transformed
//-- vertices need to be updated.
myTransformMatrix.makeMCStoWCStransform(myPosition,myAngle);
//-- transform the polyhedron model coordinates to world coords.
myTransformMatrix.transform(thePolyhedron.getVertices(),transformedVertices);
//--
positionIsDirty=angleIsDirty=false;
}
//-- project the WCS to the screen with the supplied camera
//-- and then call the paint method of the polyhedron with
//-- the returned 2d array
thePolyhedron.paint(g,camera.project(transformedVertices));
}
}
A few other classes are needed as well: /********************
matrixclasses.java
*********************/
/**
* A generic 3d matrix class that implements the rotation
* about the principal axis, translation and scaling.
*/
class fGeneric3dMatrix extends Object {
double xx, xy, xz, xo;
double yx, yy, yz, yo;
double zx, zy, zz, zo;
/**
* Constructs the identity matrix.
*/
public fGeneric3dMatrix(){
makeIdentity();
}
/**
* Resets the matrix.
*/
public void makeIdentity(){
xx = 1; xy = 0; xz = 0; xo = 0;
yx = 0; yy = 1; yz = 0; yo = 0;
zx = 0; zy = 0; zz = 1; zo = 0;
}
/**
* "Smart" multiplies a rotation about Z-axis
*/
public void concatRz(double az){
double ct = Math.cos(az);
double st = Math.sin(az);
double Nyx = (yx * ct + xx * st);
double Nyy = (yy * ct + xy * st);
double Nyz = (yz * ct + xz * st);
double Nyo = (yo * ct + xo * st);
double Nxx = (xx * ct - yx * st);
double Nxy = (xy * ct - yy * st);
double Nxz = (xz * ct - yz * st);
double Nxo = (xo * ct - yo * st);
xx = Nxx; xy = Nxy; xz = Nxz; xo = Nxo;
yx = Nyx; yy = Nyy; yz = Nyz; yo = Nyo;
}
/**
* "Smart" multiplies a rotation about Y-axis
*/
public void concatRy(double ay){
double ct = Math.cos(ay);
double st = Math.sin(ay);
double Nxx = (xx * ct + zx * st);
double Nxy = (xy * ct + zy * st);
double Nxz = (xz * ct + zz * st);
double Nxo = (xo * ct + zo * st);
double Nzx = (zx * ct - xx * st);
double Nzy = (zy * ct - xy * st);
double Nzz = (zz * ct - xz * st);
double Nzo = (zo * ct - xo * st);
xx = Nxx; xy = Nxy; xz = Nxz; xo = Nxo;
zx = Nzx; zy = Nzy; zz = Nzz; zo = Nzo;
}
/**
* "Smart" multiplies a rotation about X-axis
*/
public void concatRx(double ax){
double ct = Math.cos(ax);
double st = Math.sin(ax);
double Nyx = (yx * ct + zx * st);
double Nyy = (yy * ct + zy * st);
double Nyz = (yz * ct + zz * st);
double Nyo = (yo * ct + zo * st);
double Nzx = (zx * ct - yx * st);
double Nzy = (zy * ct - yy * st);
double Nzz = (zz * ct - yz * st);
double Nzo = (zo * ct - yo * st);
yx = Nyx; yy = Nyy; yz = Nyz; yo = Nyo;
zx = Nzx; zy = Nzy; zz = Nzz; zo = Nzo;
}
/**
* "Smart" multiplies a translation
*/
public void concatT(double x,double y,double z){
xo+=x; yo+=y; zo+=z;
}
/**
* "Smart" multiplies scaling
*/
public void concatS(double sx,double sy,double sz){
xx *= sx; xy *= sx; xz *= sx; xo *= sx;
yx *= sy; yy *= sy; yz *= sy; yo *= sy;
zx *= sz; zy *= sz; zz *= sz; zo *= sz;
}
/**
* Multiplies the vector "ps" of 3d points and stores the result
* in "pd".
*/
public void transform(fArrayOf3dPoints ps,fArrayOf3dPoints pd){
for (int i=0; i<ps.npoints; i++) {
double x=ps.x[i]; double y=ps.y[i]; double z=ps.z[i];
pd.x[i] = x*xx + y*xy + z*xz + xo;
pd.y[i] = x*yx + y*yy + z*yz + yo;
pd.z[i] = x*zx + y*zy + z*zz + zo;
}
}
}
/**
* A 3d matrix that hides the making of the different
* transforms
*/
class fMatrix3d extends fGeneric3dMatrix {
/**
* construct the matrix
*/
public fMatrix3d(){
super();
}
/**
* let matrix contain the MCS to WCS transform
*/
public void makeMCStoWCStransform(fPoint3d pos,fAngle3d agl,fPoint3d scale){
makeIdentity();
concatS(scale.x,scale.y,scale.z);
concatRx(agl.x);
concatRy(agl.y);
concatRz(agl.z);
concatT(pos.x,pos.y,pos.z);
}
/**
* let matrix contain the MCS to WCS transform, without scaling
*/
public void makeMCStoWCStransform(fPoint3d pos,fAngle3d agl){
makeIdentity();
concatRx(agl.x);
concatRy(agl.y);
concatRz(agl.z);
concatT(pos.x,pos.y,pos.z);
}
/**
* let matrix contain the WCS to MCS transform
*/
public void makeWCStoVCStransform(fPoint3d pos,fAngle3d agl){
makeIdentity();
concatT(-pos.x,-pos.y,-pos.z);
concatRz(-agl.z);
concatRy(-agl.y);
concatRx(-agl.x);
}
public void makeLookAtPointTransform(fPoint3d p0,fPoint3d p1){
fPoint3d vecZaxis=new fPoint3d(p0,p1);
vecZaxis.normalize(1);
fPoint3d vecXaxis=new fPoint3d();
vecXaxis.vectorProduct(new fPoint3d(0,1,0),p1);
vecXaxis.normalize(1);
fPoint3d vecYaxis=new fPoint3d();
vecYaxis.vectorProduct(vecZaxis,vecXaxis);
xo=-p0.x; yo=-p0.y; zo=-p0.z;
xx=vecXaxis.x; xy=vecXaxis.y; xz=vecXaxis.z;
yx=vecYaxis.x; yy=vecYaxis.y; yz=vecYaxis.z;
zx=vecZaxis.x; zy=vecZaxis.y; zz=vecZaxis.z;
}
}
Here are the helper classes:
/*********************
polygonclasses.java
**********************/
import java.awt.*;
import java.io.*;
/**
* Describes an abstract indexing polygon.
*/
abstract class fIndexingPolygon extends Object{
/**
* construct a polygon with the supplied indices
*/
protected fIndexingPolygon(int indices[],int n){
myIndices=indices;
nbrIndices=n;
}
/**
* construct a polygon from a stream
*/
protected fIndexingPolygon(InputStream is) throws IOException {
fromString(is);
}
/**
* paints a polygon. the 2d list of coordiantes must be supplied
*/
public abstract void paint(Graphics g,int x[],int y[]);
/**
* read a polygon from a stream
*/
public void fromString(InputStream is) throws IOException {
//-- make a stream tokenizer
StreamTokenizer stream = new StreamTokenizer (is);
stream.commentChar('#');
//-- get the # of indicies in this polygon
stream.nextToken(); nbrIndices=(int)stream.nval;
//-- allocate the vector
myIndices=new int[nbrIndices];
//-- read all indices
for(int i=0;i<nbrIndices;i++){
stream.nextToken(); myIndices[i]=(int)stream.nval;
}
}
/**
* make a string representation of a polygon
*/
public String toString(){
String str=new String();
str=str+nbrIndices;
for(int n=0;n<nbrIndices;n++){
str=str+" "+myIndices[n];
}
return str;
}
/**
* pokes out the 2d coordiantes and stores them into the
* scratch polygon.
*/
protected void copyIndexedPoints(int x[],int y[]){
for(int n=0;n<nbrIndices;n++){
int i=myIndices[n];
ourScratchPoly.xpoints[n]=x[i];
ourScratchPoly.ypoints[n]=y[i];
}
ourScratchPoly.npoints=nbrIndices;
}
/**
* determine the orientation of the scratch polygon.
* if the result is positive then it is CW.
*/
protected static int orientation() {
int p1x=ourScratchPoly.xpoints[1],p1y=ourScratchPoly.ypoints[1];
//-- vector from vertex #1 to vertex #2
int v1x=ourScratchPoly.xpoints[2]-p1x;
int v1y=ourScratchPoly.ypoints[2]-p1y;
//-- vector from vertex #1 to vertex #0
int v2x=ourScratchPoly.xpoints[0]-p1x;
int v2y=ourScratchPoly.ypoints[0]-p1y;
//-- return the determinant of the vectors
return v1x*v2y-v2x*v1y;
}
/**
* make a clone of this polygon
*/
public abstract fIndexingPolygon makeClone();
/**
* the "scratch" polygon that is used for painting
*/
protected static Polygon ourScratchPoly=new Polygon(new int[50],new int[50],50);
/**
* the indices that define this polygon
*/
protected int myIndices[];
/**
* number of indices in this polygon.
*/
protected int nbrIndices;
}
/**
* A solid color polygon.
*/
class fFilledPolygon extends fIndexingPolygon {
/**
* The color of this polygon.
*/
protected fColor myColor;
/**
* Create a polygon with the supplied data.
*/
public fFilledPolygon(int indices[],int n,fColor color){
super(indices,n);
myColor=color;
}
/**
* Create a polygon from a stream.
*/
public fFilledPolygon(InputStream is) throws IOException {
super(is);
}
/**
* paints the polygon if it is cw
*/
public void paint(Graphics g,int x[],int y[]){
//-- copy the indexed coordiantes from the 2d list to
//-- the scratch-pad
copyIndexedPoints(x,y);
render(g);
}
/**
* The actual rendering.
*/
protected void render(Graphics g){
//-- check orientation
if(orientation()>0){
g.setColor(myColor.getColor());
g.fillPolygon(ourScratchPoly);
}
}
/**
* overrides fIndexingPolygon.toString()
* the color must also be written to the string.
*/
public String toString(){
//-- make the string for fIndexingPolygon
String str=super.toString();
//-- add the color and line break
str=str+" "+myColor.toString()+"\n";
return str;
}
/**
* overrides fIndexingPolygon.toString()
* the color must also be read from the stream.
*/
public void fromString(InputStream is) throws IOException {
super.fromString(is);
//-- read the color
myColor=new fColor(is);
}
/**
* Makes a clone of this polygon.
*/
public fIndexingPolygon makeClone(){
int i[];
System.arraycopy(myIndices,0,i=new int[nbrIndices],0,nbrIndices);
return new fFilledPolygon(i,nbrIndices,myColor.makeClone());
}
}
And a few more:
public class fArrayOf2dPoints extends Object {
int x[],y[];
int npoints;
public fArrayOf2dPoints(int x0[],int y0[],int n){
x=x0; y=y0; npoints=n;
}
}
Then this one:
import java.io.*;
/**
* A class that encapsulates and array of 3d points.
*/
public class fArrayOf3dPoints extends Object {
double x[],y[],z[];
int npoints;
/**
* Constructs an array of 3d points with the supplied vectors.
*/
fArrayOf3dPoints(double x0[],double y0[],double z0[],int n){
x=x0; y=y0; z=z0; npoints=n;
}
/**
* Constructs an empty array of 3d points with size "n"
*/
fArrayOf3dPoints(int n){
npoints=n;
x=new double[n]; y=new double[n]; z=new double[n];
}
/**
* construct an array of 3d points from a stream
*/
fArrayOf3dPoints(InputStream is) throws IOException{
fromString(is);
}
/**
* ovrrides the Object method
*/
public String toString(){
String str=new String();
//-- the number of vertices
str=" "+npoints+"\n";
//-- concat the coordinates to the string
for(int n=0;n<npoints;n++){
str=str+x[n]+" "+y[n]+" "+z[n]+"\n";
}
return str;
}
/**
* Returns a clone.
*/
fArrayOf3dPoints makeClone(){
double xnew[],ynew[],znew[];
System.arraycopy(x,0,xnew=new double[npoints],0,npoints);
System.arraycopy(y,0,ynew=new double[npoints],0,npoints);
System.arraycopy(z,0,znew=new double[npoints],0,npoints);
return new fArrayOf3dPoints(xnew,ynew,znew,npoints);
}
/**
* Reads an array from a stream
*/
void fromString(InputStream is) throws IOException {
//-- make a stream tokenizer
StreamTokenizer stream = new StreamTokenizer (is);
stream.commentChar('#');
//-- get the # points
stream.nextToken(); npoints=(int)stream.nval;
//-- create the vectors
x=new double[npoints];
y=new double[npoints];
z=new double[npoints];
//-- read the coordiantes
for(int n=0;n<npoints;n++){
stream.nextToken(); x[n]=(double)stream.nval;
stream.nextToken(); y[n]=(double)stream.nval;
stream.nextToken(); z[n]=(double)stream.nval;
}
}
}
Then this one:
import java.awt.*;
import java.io.*;
/**
* Wraps the java.awt.Color class provided by Java
*/
public class fColor extends Object {
public int r,g,b;
protected Color myBaseColor;
/**
* construct a color with the RGB supplied.
*/
public fColor(int r0,int g0,int b0){
r=r0; g=g0; b=b0;
myBaseColor=new Color(r,g,b);
}
/**
* constructs a color from a stream
*/
public fColor(InputStream is) throws IOException{
fromString(is);
myBaseColor=new Color(r,g,b);
}
/**
* returns the base color
*/
public Color getColor(){
return myBaseColor;
}
/**
* read the color from a stream
*/
public void fromString(InputStream is) throws IOException{
//-- make a stream tokenizer
StreamTokenizer stream = new StreamTokenizer (is);
stream.commentChar('#');
//-- read the RGB triple
stream.nextToken(); r=(int)stream.nval;
stream.nextToken(); g=(int)stream.nval;
stream.nextToken(); b=(int)stream.nval;
}
/**
* make a string representation
*/
public String toString(){
return new String(" "+r+" "+g+" "+b+" ");
}
/**
* Makes a clone of this color.
*/
public fColor makeClone(){
return new fColor(r,g,b);
}
}
So we compile everything and here's
the applet.
Once we see we are ready to understand it, and it's simple.
Last updated: Dec 26, 2001 by Adrian German for A348/A548