Code for the Wallpaper Applet
Written by Frank Farris
If you want to use this code, just remove
the html tags at the beginning and end of the file.
This is displayed as pre-formatted text, so the edges
may be cut off if your browser window isn't big enough.
import java.applet.Applet;
import java.awt.*;
import java.lang.*;
public class WallpaperMaker extends Applet {
Wallpaper wall;
WallpaperControls controls;
CardLayout card;
public void init() {
resize(500,500);
setLayout(new BorderLayout());
wall = new Wallpaper();
controls = new WallpaperControls(wall);
add("Center",wall);
add("South", controls);
}
public void start(){
controls.enable();
}
public void stop(){ controls.disable();}
// this event handler only handles cataclysmic events
public boolean handleEvent(Event evt)
{ if (evt.id==Event.WINDOW_DESTROY){ System.exit(0);}
return false;}
public String getAppletInfo() {
return "Wallpaper by Farris";
}
}// end of applet
class Term {
// has two integer frequencies
public int n;
public int m;
// with a real coefficient out front
public double coeff;
// a default constructor to make a null term
public Term(){n=0;m=0;coeff=0.0;}
public Term(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// and it knows how to return a value
public double value(double x, double y){
// this is a vacuous function that returns 0
return 0.0;};
public String formula(){String tempString= " ";
tempString=tempString+" ";
return tempString;};
}// end of Term class -- this has descendants below
class ssTerm extends Term {
// has two integer frequencies
public int n;
public int m;
// with a real coefficient out front
public double coeff;
// a default constructor to make a null term
public ssTerm(){n=0;m=0;coeff=0.0;}
public ssTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// and it knows how to return a value
public double value(double x, double y){
// this is a sine-sine term
return coeff*Math.sin(n*x)*Math.sin(m*y);};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"sin("+n+"X)"+"sin("+m+"Y)";
return tempString;};
}// end of Term class -- later this will have descendants
class ccTerm extends Term {
// I guess it needs its own constructors
public ccTerm(){n=0;m=0;coeff=0.0;}
public ccTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
//this is a cosine-cosine term
public double value(double x, double y){
return coeff*Math.cos(n*x)*Math.cos(m*y);};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"cos("+n+"X)"+"cos("+m+"Y)";
return tempString;};
}// end of cc-Term class
class csTerm extends Term {
public csTerm(){n=0;m=0;coeff=0.0;}
public csTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
return coeff*Math.cos(n*x)*Math.sin(m*y);};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"cos("+n+"X)"+"sin("+m+"Y)";
return tempString;};
}// end of cs-Term class
class scTerm extends Term {
public scTerm(){n=0;m=0;coeff=0.0;}
public scTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*Math.sin(n*x)*Math.cos(m*y);};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"sin("+n+"X)"+"cos("+m+"Y)";
return tempString;};
}// end of sc-Term class
class shexTerm extends Term {
public shexTerm(){n=0;m=0;coeff=0.0;}
public shexTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.sin(n*x+m*y)+Math.sin(m*x-(n+m)*y)
+Math.sin(-(n+m)*x+n*y));
};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"S("+n+", "+m+")";
return tempString;};
}// end of shexTerm class
class chexTerm extends Term {
public chexTerm(){n=0;m=0;coeff=0.0;}
public chexTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.cos(n*x+m*y)+Math.cos(m*x-(n+m)*y)
+Math.cos(-(n+m)*x+n*y));};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"C("+n+", "+m+")";
return tempString;};
}// end of chexTerm class
class csqTerm extends Term {
public csqTerm(){n=0;m=0;coeff=0.0;}
public csqTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.cos(n*x)*Math.cos(m*y)+Math.cos(m*x)*Math.cos(n*y));};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"C("+n+", "+m+")";
return tempString;};
}// end of csqTerm class
class csqnegTerm extends Term {
public csqnegTerm(){n=0;m=0;coeff=0.0;}
public csqnegTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.cos(n*x)*Math.cos(m*y)-Math.cos(m*x)*Math.cos(n*y));};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"C-("+n+","+m+")";
return tempString;};
}// end of csqnegTerm class
class ssqTerm extends Term {
public ssqTerm(){n=0;m=0;coeff=0.0;}
public ssqTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.sin(n*x)*Math.sin(m*y)-Math.sin(m*x)*Math.sin(n*y));};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"S("+n+", "+m+")";
return tempString;};
}// end of ssqTerm class
class ssqnegTerm extends Term {
public ssqnegTerm(){n=0;m=0;coeff=0.0;}
public ssqnegTerm(double coeff, int n, int m){
this.coeff=coeff; this.n=n ; this.m=m;
};
// the only new thing is that this overrides previous value fcn
public double value(double x, double y){
// this is just an example for a rectangular cell
return coeff*(Math.sin(n*x)*Math.sin(m*y)+Math.sin(m*x)*Math.sin(n*y));};
public String formula(){String tempString= " ";
tempString=tempString+coeff+"S-("+n+", "+m+")";
return tempString;};
}// end of ssqnegTerm class
////////////////////////////////////////////
///////////////////////////////////////////
class WallpaperFunction {
public static final double pi=Math.PI;
// should be an array of Terms with initializer and fcn to return value
public int numTerms= 0;
public Term[] terms;
// makes a default wallpaper with twenty terms
public WallpaperFunction(){terms = new Term[20];
for(int k=0;k < 20;k++){terms[k]=new Term();}
};
// computes output value of function from world coords
public double functionValue(double x, double y){
double xLattice, yLattice;
double sumValue=0;
xLattice=x;
yLattice=1.414*y;
for (int j=0; j < numTerms; j++){
sumValue=sumValue+terms[j].value(xLattice,yLattice);}
return sumValue;
}
// computes string for formula
public String formula(){
String temp="";
for (int p=0;p < numTerms;p++){temp=temp+terms[p].formula()+" + ";}
return temp+" ";};
// enables us to add a term of any type -- fcn has unused flexibility
// in addWhere variable
public void addTerm(Term tempTerm, int addWhere){
terms[addWhere]=tempTerm;
numTerms=numTerms+1;}
// deletes last term
public void deleteTerm(int termNum){
numTerms=numTerms-1;
Term nullTerm = new Term(0.0,0,0);
terms[termNum]=nullTerm;}
public double wallMax(){
double tempMax=0;
double x,y;
for (int i=0; i < 100;i++){
for(int k=0;k < 100;k++){
x = i*pi/50.0;y=k*pi/50.0;
double tempHeight=0;
for (int j=0; j < numTerms+1;j++){
tempHeight=tempHeight+terms[j].value(x,y);
};
tempHeight=Math.abs(tempHeight);
if(tempHeight > tempMax){tempMax=tempHeight;};};}
return tempMax;}
}
/////////////////////////////////////////////
// a hexWallpaperFunction will only overwrite value function
class hexWallpaperFunction extends WallpaperFunction{
public static final double qr = Math.sqrt(3);
public hexWallpaperFunction(){terms = new Term[20];
for(int k=0;k <20;k++){terms[k]=new Term();}
};
// computes output value of function from world coords
public double functionValue(double x, double y){
double xLattice, yLattice;
double sumValue=0;
xLattice=x+y/qr;
yLattice=2*y/qr;
for (int j=0; j < numTerms;j++){
sumValue=sumValue+terms[j].value(xLattice,yLattice);}
return sumValue;
}
} // end of hexWallpaperFunction class
// a sqWallpaperFunction will make wallpaper in square cells
class sqWallpaperFunction extends WallpaperFunction{
public sqWallpaperFunction(){terms = new Term[20];
for(int k=0;k < 20;k++){terms[k]=new Term();}
};
// computes output value of function from world coords
public double functionValue(double x, double y){
double sumValue=0;
for (int j=0; j < numTerms;j++){
sumValue=sumValue+terms[j].value(x,y);}
return sumValue;
}
} // end of sqWallpaperFunction class
///////////////////////////////////////////
///////////////////////////////////////////
// here is the wallpaper class -- the thing that owns a function and
// knows how to paint it
class Wallpaper extends Panel{
// this is the thing that displays the wallpaper function it owns.
// size of view window:
public int ViewX = 150;
public int ViewY = 150;
// the image for off-screen drawing
Image image, newimage;
Graphics offg;
public WallpaperFunction f;
// makes the default wallpaper empty
// user must add terms
public Wallpaper(){
f=new WallpaperFunction();
};
public boolean willRecompute = true;
public void paint(Graphics g) {
g.setColor(Color.black);
g.drawString(f.formula(),0,ViewY+120);
// somehow it matters to call createImage from within paint
// doing this when image was declared resulted in NullPointerException
newimage =createImage(ViewX+100, ViewY+100);
offg= newimage.getGraphics();
//This recomputes the image and paints it in an offscreen place
if (willRecompute==true){
// first paint a big white rectangle
offg.setColor(Color.white);
offg.fillRect(0,0,ViewX+100,ViewY+100);
int altitude;
double x, y;
double wallMax=f.wallMax();
if (wallMax==0){wallMax=1;};
for (int j=50; j < (ViewY+50); j++) {
y=12.0*j/(double)ViewY;
for (int i=50; i < (ViewX+50); i++) {
x=12.0*i/(double)ViewX;
altitude=(byte)(255.0*f.functionValue(x,y)/wallMax)+128;
Color color=new Color(altitude ,altitude%128 ,255-altitude);
offg.setColor(color);
offg.fillRect(i,j,1,1);
}
} ;
// this replaces existing image with newly computed one
image = newimage;
willRecompute=false;
}
// question: "this" below implements interface ImageObserver. What
// does it do?
g.drawImage(image,0,0,Color.white,this);
// end of paint method
}} // end of wallpaperView class
/////////////////////////////////////////////////////////
// Wallpaper Controls class
class WallpaperControls extends Panel {
public TextField coeffVal,nVal,mVal;
public Wallpaper w;
public Panel buttoncards;
public Panel pCoeff;
public Panel selector;
public CardLayout card;
public WallpaperControls(Wallpaper w) {
this.w=w;
setLayout(new BorderLayout());
selector = new Panel();
selector.setLayout(new GridLayout(3,1));
selector.add(new Button("hex"));
selector.add(new Button("rect"));
selector.add(new Button("square"));
add("West",selector);
buttoncards = new Panel();
card = new CardLayout();
buttoncards.setLayout(card);
buttoncards.add("hex",new HexButton());
buttoncards.add("square", new SquareButton());
buttoncards.add("rect", new RectButton());
card.show(buttoncards, "rect");
add("Center",buttoncards);
// this panel is where we enter new data - give default values
Panel pCoeff = new Panel();
pCoeff.setLayout(new GridLayout(3,2));
pCoeff.add( new Label("coeff"));
pCoeff.add(coeffVal = new TextField("1",6));
pCoeff.add(new Label("x freq"));
pCoeff.add(nVal=new TextField("0",4));
pCoeff.add(new Label("y freq"));
pCoeff.add(mVal = new TextField("0",4));
add("East",pCoeff);
}
// event handler for WallpaperControl
public boolean action(Event ev, Object arg){
if (ev.target instanceof Button)
//whichever button is pressed, we read the textfields
int n_ = Integer.parseInt(nVal.getText().trim());
int m_ =Integer.parseInt(mVal.getText().trim());
double newCoeff =
Float.valueOf(coeffVal.getText()).floatValue();
// read buttons from HexButton
if ("add S(n,m) hex term".equals(arg))
{ shexTerm temp= new shexTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add C(n,m) hex term".equals(arg))
{chexTerm temp= new chexTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
// read buttons from RectButton
if ("add cos-cos term".equals(arg))
{ ccTerm temp= new ccTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add sin-cos term".equals(arg))
{ scTerm temp= new scTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add cos-sin term".equals(arg))
{ csTerm temp= new csTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add sin-sin term".equals(arg))
{ssTerm temp= new ssTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
// read buttons on SquareButton
if ("add C(n,m) term".equals(arg))
{ csqTerm temp= new csqTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add S(n,m) term".equals(arg))
{ ssqTerm temp= new ssqTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add C-(n,m) term".equals(arg))
{ csqnegTerm temp= new csqnegTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("add S-(n,m) term".equals(arg))
{ssqnegTerm temp= new ssqnegTerm(newCoeff, n_,m_);
w.f.addTerm(temp,w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
// read buttons common to all
if ("delete last term".equals(arg))
{ w.f.deleteTerm(w.f.numTerms);
w.repaint(0,w.ViewY+100,600,w.ViewY+120);
};
if ("redraw".equals(arg))
{ w.willRecompute=true;
w.repaint(0,0,w.ViewX+100,w.ViewY+120);
};
if ("hex".equals(arg))
{ w.f = new hexWallpaperFunction();
w.willRecompute=true;
card.show(buttoncards,"hex");
w.repaint();
repaint();
};
if ("rect".equals(arg))
{ w.f = new WallpaperFunction();
w.willRecompute=true;
card.show(buttoncards, "rect");
w.repaint();
repaint();
};
if ("square".equals(arg))
{ w.f = new sqWallpaperFunction();
w.willRecompute=true;
card.show(buttoncards, "square");
w.repaint();
repaint();
};
return true;} else
{return false;};
}// end action
} // end WallpaperControls class
// ButtonPanel is made to be extended in three ways
class ButtonPanel extends Panel{
public ButtonPanel(){};
}// that's all
class HexButton extends ButtonPanel{
public HexButton(){
setLayout(new GridLayout(2,2));
// put four buttons in the panel -- mirrors?
add(new Button("add C(n,m) hex term"));
add(new Button("add S(n,m) hex term"));
add(new Button("delete last term"));
add(new Button("redraw"));
};
}; //end class
class RectButton extends ButtonPanel{
public RectButton(){
setLayout(new GridLayout(3,2));
add(new Button("add cos-cos term"));
add(new Button("add cos-sin term"));
add(new Button("add sin-cos term"));
add(new Button("add sin-sin term"));
add(new Button("delete last term"));
add(new Button("redraw"));
}
} // end of RectButton class
class SquareButton extends ButtonPanel{
public SquareButton(){
setLayout(new GridLayout(3,2));
add(new Button("add C(n,m) term"));
add( new Button("add S(n,m) term"));
add(new Button("add C-(n,m) term"));
add(new Button("add S-(n,m) term"));
add(new Button("delete last term"));
add(new Button("redraw"));
}
} // end of SquareButton class
Communications in Visual Mathematics, vol 1, no 1, August 1998.
Copyright © 1998,
The Mathematical Association of America.
All rights reserved.
Created: 01 Jul 1998 ---
Last modified: 18 Aug 1998 23:59:59
Comments to: CVM@maa.org