Complex Function Grapher
CGApplet.java
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
/**
This applet provides an interface to a CompGraph Object which will
graph a complex function using color to plot a 4th dimension.
Last updated February 26, 2001
(copyright 1997-2001)
@version 1.0
@author Andrew G. Bennett
*/
public class CGApplet extends Applet implements ItemListener {
/**
Initializations
*/
public void init() {
super.init();
fzactive=true;
helpactive=true;
dpactive=true;
// No Layout Manager
setLayout(null);
addNotify();
resize(500,400);
// Help Screen Panel
helpPanel=new Panel(null);
helpPanel.setBounds(70,25,360,310);
helpPanel.setBackground(Color.lightGray);
helpPanel.setVisible(false);
add(helpPanel);
helptextString=new String(
"Graphing a complex function is difficult because you\n"
+"need 2 (real) dimensions for the domain and 2 (real)\n"
+"dimensions for the range - a total of 4 dimensions.\n"
+"In this applet, the domain of a complex function is\n"
+"graphed on the base plane. The range is graphed using\n"
+"polar coordinates. The modulus (magnitude) of the\n"
+"complex function is graphed on the vertical axis. The\n"
+"argument (angle) is graphed by using different colors:\n"
+"light blue for positive real, dark blue (shading to\n"
+"purple) for positive imaginary, red for negative real,\n"
+"and yellow-green for negative imaginary. This allows\n"
+"four dimensions to be represented in three spatial\n"
+"dimensions, which are then projected onto a two\n"
+"dimensional screen using a simple orthogonal\n"
+"projection.\n\n"
+"Enter complex functions into the f(z) = text box using\n"
+"standard calculator notation. You must use * for\n"
+"multiplication, i.e. 2*z not 2z. Functions must have\n"
+"parentheses, i.e. sin(z) not sin z. The parser\n"
+"understands the following operations, functions, and\n"
+"constants: +, -, *, /, ^, sqrt(), sin(), cos(), tan(),\n"
+"exp(), ln(), log() (synonymous with ln), sinh(), cosh(),\n"
+"abs(), mod() (synonymous with abs), arg(), conj(),\n"
+"e, pi, i.\n\n"
+"To adjust the domain of the graph, right-click (or\n"
+"shift-click if you have a one-button mouse) on the\n"
+"graph. The domain editor only accepts numerical input,\n"
+"i.e. 3.14 not pi.");
helpTextArea=new TextArea(helptextString,20,55,TextArea.SCROLLBARS_VERTICAL_ONLY);
helpTextArea.setBounds(10,10,340,270);
helpTextArea.setEditable(false);
helpPanel.add(helpTextArea);
helpcloseButton=new Button("Close");
helpcloseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
closeHelp();
}
});
helpcloseButton.setBounds(145,285,70,20);
helpPanel.add(helpcloseButton);
// Edit Domain Panel
dp=new Panel(null);
dp.setBounds(125,85,250,190);
dp.setBackground(Color.lightGray);
dp.setVisible(false);
add(dp);
// Re(z) Values
rLabel=new Label("Re(z):");
rLabel.setBounds(5,10,40,20);
dp.add(rLabel);
rminLabel=new Label("min ",Label.RIGHT);
rminLabel.setBounds(45,10,30,20);
dp.add(rminLabel);
rminTextField=new TextField("-2.0");
rminTextField.setBounds(75,10,70,20);
dp.add(rminTextField);
rmaxLabel=new Label("max ",Label.RIGHT);
rmaxLabel.setBounds(145,10,30,20);
dp.add(rmaxLabel);
rmaxTextField=new TextField("2.0");
rmaxTextField.setBounds(175,10,70,20);
dp.add(rmaxTextField);
// Im(z) Values
iLabel=new Label("Im(z):");
iLabel.setBounds(5,50,40,20);
dp.add(iLabel);
iminLabel=new Label("min ",Label.RIGHT);
iminLabel.setBounds(45,50,30,20);
dp.add(iminLabel);
iminTextField=new TextField("-2.0");
iminTextField.setBounds(75,50,70,20);
dp.add(iminTextField);
imaxLabel=new Label("max ",Label.RIGHT);
imaxLabel.setBounds(145,50,30,20);
dp.add(imaxLabel);
imaxTextField=new TextField("2.0");
imaxTextField.setBounds(175,50,70,20);
dp.add(imaxTextField);
// |f(z)| Values
fLabel=new Label("|f(z)|:");
fLabel.setBounds(5,90,40,20);
dp.add(fLabel);
fCGroup=new CheckboxGroup();
fautoCheckbox=new Checkbox("auto",true,fCGroup);
fautoCheckbox.setBounds(65,90,80,20);
fautoCheckbox.addItemListener(this);
dp.add(fautoCheckbox);
fmanCheckbox=new Checkbox("manual",false,fCGroup);
fmanCheckbox.setBounds(65,120,80,20);
fmanCheckbox.addItemListener(this);
dp.add(fmanCheckbox);
fminLabel=new Label("min ",Label.RIGHT);
fminLabel.setForeground(Color.gray);
fminLabel.setBounds(145,90,30,20);
dp.add(fminLabel);
fminTextField=new TextField("0.0");
fminTextField.setForeground(Color.gray);
fminTextField.setBounds(175,90,70,20);
fminTextField.setEditable(false);
// Prevent it gaining focus if fauto checked
fminTextField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
if (fautoCheckbox.getState()) {
fminLabel.requestFocus();
}
}
});
dp.add(fminTextField);
fmaxLabel=new Label("max ",Label.RIGHT);
fmaxLabel.setForeground(Color.gray);
fmaxLabel.setBounds(145,120,30,20);
dp.add(fmaxLabel);
fmaxTextField=new TextField("3.0");
fmaxTextField.setForeground(Color.gray);
fmaxTextField.setBounds(175,120,70,20);
fmaxTextField.setEditable(false);
// Prevent it gaining focus if fauto checked
fmaxTextField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
if (fautoCheckbox.getState()) {
fmaxLabel.requestFocus();
}
}
});
dp.add(fmaxTextField);
// Domain Buttons
okButton=new Button("OK");
okButton.setBounds(35,150,60,20);
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
okdp();
}
});
dp.add(okButton);
resetButton=new Button("Defaults");
resetButton.setBounds(95,150,60,20);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
resetdp();
}
});
dp.add(resetButton);
cancelButton=new Button("Cancel");
cancelButton.setBounds(155,150,60,20);
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canceldp();
}
});
dp.add(cancelButton);
// Message Label (for errors)
messLabel=new Label("",Label.CENTER);
messLabel.setForeground(Color.red);
messLabel.setBounds(5,170,240,20);
dp.add(messLabel);
// CompGraph to plot graph
c3d=new CompGraph();
c3d.setBackground(Color.black);
c3d.setBounds(45,5,410,350);
c3d.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if ((evt.getModifiers()&InputEvent.BUTTON3_MASK)>0
|| evt.isShiftDown()) {
showdp();
}
}
});
add(c3d);
// Label "f(z) ="
fzLabel=new Label("f(z) =",Label.CENTER);
fzLabel.setBounds(10,360,50,20);
add(fzLabel);
// TextField to input f(z)
fzTextField=new TextField("z");
fzTextField.setBounds(60,360,265,20);
fzTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!fzactive) return;
emLabel.setText("");
try {
c3d.setfct(fzTextField.getText());
c3d.repaint();
} catch (Exception except) {
emLabel.setText("Unable to evaluate f(z)");
}
}
});
add(fzTextField);
// Change view to "top" button
tvButton=new Button("Top View");
tvButton.setBounds(340,360,70,20);
tvButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!fzactive) return;
c3d.setView("top");
emLabel.setText("");
try {
c3d.setfct(fzTextField.getText());
c3d.repaint();
} catch (Exception except) {
emLabel.setText("Unable to evaluate f(z)");
}
}
});
add(tvButton);
// Change view to "side" button
svButton=new Button("Side View");
svButton.setBounds(410,360,70,20);
svButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!fzactive) return;
c3d.setView("side");
emLabel.setText("");
try {
c3d.setfct(fzTextField.getText());
c3d.repaint();
} catch (Exception except) {
emLabel.setText("Unable to evaluate f(z)");
}
}
});
add(svButton);
helpButton=new Button("Help");
helpButton.setBounds(410,380,70,20);
helpButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (!helpactive) return;
helpPanel.setVisible(true);
fzTextField.setEditable(false);
fzactive=false;
dpactive=false;
}
});
add(helpButton);
// Error Message Label
emLabel=new Label("",Label.LEFT);
emLabel.setForeground(Color.red);
emLabel.setBounds(60,380,265,20);
add(emLabel);
}
/**
Activate and Gray |f(z)| min & max
@param evt Change in auto/manual |f(z)| limit checkboxes
*/
public void itemStateChanged(ItemEvent evt) {
if (fautoCheckbox.getState()) { // Gray |f(z)| min & max
fminLabel.setForeground(Color.gray);
fminTextField.setForeground(Color.gray);
fminTextField.setEditable(false);
fmaxLabel.setForeground(Color.gray);
fmaxTextField.setForeground(Color.gray);
fmaxTextField.setEditable(false);
} else { // Activate |f(z)| min & max
fminLabel.setForeground(Color.black);
fminTextField.setForeground(Color.black);
fminTextField.setEditable(true);
fmaxLabel.setForeground(Color.black);
fmaxTextField.setForeground(Color.black);
fmaxTextField.setEditable(true);
}
}
// Show Domain Panel
private void showdp() {
if (!dpactive) return;
rminTextField.setText(String.valueOf(c3d.getxmin()));
rmaxTextField.setText(String.valueOf(c3d.getxmax()));
iminTextField.setText(String.valueOf(c3d.getymin()));
imaxTextField.setText(String.valueOf(c3d.getymax()));
fminTextField.setText(String.valueOf(c3d.getzmin()));
fmaxTextField.setText(String.valueOf(c3d.getzmax()));
if (c3d.getzauto()) {
fautoCheckbox.setState(true);
fminLabel.setForeground(Color.gray);
fminTextField.setForeground(Color.gray);
fminTextField.setEditable(false);
fmaxLabel.setForeground(Color.gray);
fmaxTextField.setForeground(Color.gray);
fmaxTextField.setEditable(false);
} else {
fmanCheckbox.setState(true);
fminLabel.setForeground(Color.black);
fminTextField.setForeground(Color.black);
fminTextField.setEditable(true);
fmaxLabel.setForeground(Color.black);
fmaxTextField.setForeground(Color.black);
fmaxTextField.setEditable(true);
}
messLabel.setText("");
dp.setVisible(true);
fzactive=false;
helpactive=false;
fzTextField.setEditable(false);
}
// Domain Panel Okayed
private void okdp() {
double rmin,rmax,imin,imax,fmin,fmax;
// Validate Input
try {
rmin=Double.valueOf(rminTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse Re(z) min");
rminTextField.requestFocus();
return;
}
try {
rmax=Double.valueOf(rmaxTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse Re(z) max");
rmaxTextField.requestFocus();
return;
}
try {
imin=Double.valueOf(iminTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse Im(z) min");
iminTextField.requestFocus();
return;
}
try {
imax=Double.valueOf(imaxTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse Im(z) max");
imaxTextField.requestFocus();
return;
}
fmin=0;fmax=3;
if (fmanCheckbox.getState()) {
try {
fmin=Double.valueOf(fminTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse |f(z)| min");
fminTextField.requestFocus();
return;
}
try {
fmax=Double.valueOf(fmaxTextField.getText()).doubleValue();
} catch (NumberFormatException except) {
messLabel.setText("Can't Parse |f(z)| max");
fmaxTextField.requestFocus();
return;
}
}
if (rmin>=rmax) {
messLabel.setText("Re(z) min must be less than max");
rminTextField.requestFocus();
return;
}
if (imin>=imax) {
messLabel.setText("Im(z) min must be less than max");
iminTextField.requestFocus();
return;
}
if (fmanCheckbox.getState() && (fmin>=fmax)) {
messLabel.setText("|f(z)| min must be less than max");
fminTextField.requestFocus();
return;
}
// Valid input so update domain and graph
c3d.setLimits(rmin,rmax,imin,imax);
if (fautoCheckbox.getState()) {
c3d.setzauto(true);
} else {
c3d.setzauto(false);
c3d.setzLimits(fmin,fmax);
}
c3d.setfct(fzTextField.getText());
dp.setVisible(false);
c3d.repaint();
fzTextField.setEditable(true);
fzactive=true;
helpactive=true;
}
// Domain Panel reset
private void resetdp() {
rminTextField.setText("-2.0");
rmaxTextField.setText("2.0");
iminTextField.setText("-2.0");
imaxTextField.setText("2.0");
fautoCheckbox.setState(true);
fminLabel.setForeground(Color.gray);
fminTextField.setForeground(Color.gray);
fmaxLabel.setForeground(Color.gray);
fmaxTextField.setForeground(Color.gray);
fzactive=true;
helpactive=true;
fzTextField.setEditable(true);
}
// Domain Panel Cancelled
private void canceldp() {
dp.setVisible(false);
fzactive=true;
helpactive=true;
fzTextField.setEditable(true);
}
// Close Help Panel
private void closeHelp() {
helpPanel.setVisible(false);
fzactive=true;
dpactive=true;
fzTextField.setEditable(true);
c3d.repaint();
}
//DECLARE CONTROLS
CompGraph c3d;
Panel dp,helpPanel;
GridBagConstraints constraints;
Label fzLabel,emLabel,rLabel,rminLabel,rmaxLabel,
iLabel,iminLabel,imaxLabel,
fLabel,fminLabel,fmaxLabel,messLabel;
TextField fzTextField,rminTextField,rmaxTextField,
iminTextField,imaxTextField,fminTextField,fmaxTextField;
TextArea helpTextArea;
String helptextString;
Checkbox fautoCheckbox,fmanCheckbox;
CheckboxGroup fCGroup;
Button tvButton,svButton,helpcloseButton,helpButton,
okButton,resetButton,cancelButton;
boolean fzactive,dpactive,helpactive;
}
Please report any problems with this page to
bennett@math.ksu.edu
©2001 Andrew G. Bennett