![]() |
![]() |
Motto: Never open a spaceman's helmet on an uncharted planet. |
![]() |
Here's cubes.html
:
The approach now is top-down since we want<html> <head> <title>Some cubes</title> </head> <body> <applet code="Cube.class" width=400 height=400> </applet> </body> </html>
So, here's Cube.java
:
This requires the following (data) file, calledimport 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); } } }
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
Now the generic camera.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); } }
Here's the three dimensional point:/** * 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 are the polyhedron classes, starting with the abstractpublic 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+")"); } }
Polyhedron
class:
Here's the polyhedron instance./************************************* 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); } }
A few other classes are needed as well:/*************************** 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)); } }
Here are the helper classes:/******************** 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; } }
And a few more:/********************* 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()); } }
Then this one: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; } } }
So we compile everything and here's the applet.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); } }
Once we see we are ready to understand it, and it's simple.
Last updated: Dec 26, 2001 by Adrian German for A348/A548