package gve.calc;
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import gve.calc.formula.*;
public class Bernstein extends Applet implements ItemListener,Layer,ActionListener,Runnable {
private PlotCanvas plotcan;
private Choice funcChoice,graadChoice;
Bernstein polynomial takes values of f between xmin and xmax.
Note: things go wrong when xmin!=0 or xmax!=1 |
private double xmin=0,xmax=1;
Values of the function at equidistant points between xmin and xmax |
private double [] fvalues;
private Label status;
private Button animateButton;
private boolean pleaseStop = false;
public boolean isAnimating = false;
public void init() {
setLayout(new BorderLayout());
Panel p = new Panel();
p.add(new Label("Functie:"));
Choice c;
p.add(c = new Choice());
funcChoice = c;
c.add("abs(2x-1)");
c.add("sin(pi*x)");
c.add("cos(pi*x)");
c.add("x^2");
c.add("x^3");
c.addItemListener(this);
p.add(new Label("graad:"));
p.add(c = new Choice());
graadChoice = c;
for (int i = 1; i <= 15; i++)
c.add(""+i);
c.addItemListener(this);
Button b;
p.add(b = new Button("+"));
b.addActionListener(this);
p.add(b = new Button("-"));
b.addActionListener(this);
p.add(b = new Button("Anim"));
b.addActionListener(this);
animateButton = b;
add("North",p);
add("Center",plotcan = new PlotCanvas());
plotcan.setDbuffer(true);
// plotcan.setPlotMode(PlotCanvas.INTERVALS);
plotcan.setRanges(-1,2,-1,2);
add("South",status = new Label("",Label.LEFT));
itemStateChanged(null); // create plot functions
}
public void actionPerformed(ActionEvent evt) {
String cmd = evt.getActionCommand();
if (cmd.equals("Anim")) {
new Thread(this).start();
} else if (cmd.equals("Stop")) {
pleaseStop = true;
} else if (cmd.equals("+")) {
int graad = Integer.parseInt(graadChoice.getSelectedItem());
graadChoice.select(""+(graad+1));
itemStateChanged(null);
} else if (cmd.equals("-")) {
int graad = Integer.parseInt(graadChoice.getSelectedItem());
graadChoice.select(""+(graad-1));
itemStateChanged(null);
}
}
public void sleep(int ms) {
try { Thread.sleep(ms); }
catch (InterruptedException exc) {}
}
public void run() {
if (isAnimating)
/* Don't animate twice */
return;
animateButton.setLabel("Stop");
isAnimating = true;
for (int graad = 1; graad <= 15; graad++) {
if (pleaseStop) {
pleaseStop = false;
break;
}
graadChoice.select(""+graad);
itemStateChanged(null);
plotcan.repaint(10); // repaint in 10ms
sleep(500); // wait for plot to start
while (plotcan.isPlotting()) sleep(100); // wait for plot to finish
if (!pleaseStop) sleep(1000);
}
isAnimating = false;
animateButton.setLabel("Anim");
}
public void itemStateChanged(ItemEvent evt) {
int graad = Integer.parseInt(graadChoice.getSelectedItem());
fvalues = new double[graad+1];
double [] coeffs = new double[graad+1];
String fname = funcChoice.getSelectedItem();
Formula f = null;
if (fname.equals("sin(pi*x)"))
f = new Formula(new OperatorSpace(new Identifier("sin"),new OperatorMult(new Identifier("x"),new Identifier(""+Math.PI))));
else if (fname.equals("cos(pi*x)"))
f = new Formula(new OperatorSpace(new Identifier("cos"),new OperatorMult(new Identifier("x"),new Identifier(""+Math.PI))));
else if (fname.equals("x^2"))
f = new Formula(new OperatorPow(new Identifier("x"),new Identifier("2")));
else if (fname.equals("x^3"))
f = new Formula(new OperatorPow(new Identifier("x"),new Identifier("3")));
else if (fname.equals("abs(2x-1)"))
f = new Formula(new OperatorSpace(new Identifier("abs"),
new OperatorMinus(new OperatorMult(new Identifier("2"),new Identifier("x")),new Identifier("1"))
));
plotcan.setFunction(f);
// Bernstein stuff
Evaluator ev = new MultiEvaluator();
StandardFunctions.registerFunctions(ev);
Real dv = new Real(0.0);
ev.defineVariable("x",dv);
double comb = 1; // = (n k)
for (int k = 0; k <= graad; k++) {
// voorfactor comb = (n k) berekenen
if (k == 0) comb = 1;
else comb = comb * (double)(graad-k+1) / (double)k;
// functiewaarde
dv.doubleValue = xmin + (double)k/graad*(xmax-xmin);
Part res = f.evaluate(ev);
double fx = 0;
if (res instanceof Real) {
fx = ((Real)res).doubleValue;
} else return;
fvalues[k] = fx;
// Add comb * f(x) * x^k * (1-x)^(n-k)
fx *= comb; // prefactor
{ double binom = 1; // coeff. for Newton's binomium
for (int j = 0; j <= graad-k; j++) {
if (j != 0) binom = -binom * (double)(graad-k-j+1) / (double)j;
coeffs[j+k] += binom * fx;
}
}
}
Part bernstein = null;
String txt = null;
for (int i = 0; i <= graad; i++) {
double c = coeffs[i]; // coefficient of the term x^i
if (Math.abs(c) <= 1E-10) continue;
Part term = null;
Identifier id = new Identifier(""+c);
String str;
if (i==0) {
term = id; str = ""+c;
} else if (i==1) {
term = new OperatorMult(id,new Identifier("x"));
if (c == 1) str = "x"; else str = c+"x";
} else {
term = new OperatorMult(id,new OperatorPow(new Identifier("x"),new Identifier(""+i)));
if (c == 1) str = "x^"+i; else str = c+"x^"+i;
}
if (bernstein == null) bernstein = term;
else bernstein = new OperatorPlus(bernstein,term);
if (txt == null) txt = str;
else txt += " + "+str;
}
if (bernstein == null) {
bernstein = new Identifier("0");
txt = "0";
}
status.setText(txt);
f = new Formula(bernstein);
plotcan.addFunction(f);
plotcan.setLayer(this);
}
public void paintLayer(Graphics g,int width,int height) {
// assenkruis
int y = plotcan.yToPix(0);
g.setColor(Color.blue);
g.drawLine(0,y,width,y);
int x = plotcan.xToPix(0);
g.drawLine(x,0,x,height);
x = plotcan.xToPix(1);
g.drawLine(x,y-5,x,y+5); // x=1 tick
x = plotcan.xToPix(0); y = plotcan.yToPix(1);
g.drawLine(x-5,y,x+5,y); // y=1 tick
g.setColor(Color.red);
int graad = Integer.parseInt(graadChoice.getSelectedItem());
for (int k = 0; k <= graad; k++) {
// NOTE: we suppose [xmin,xmax] = [0,1] ...
x = plotcan.xToPix((double)k / (double)graad);
y = plotcan.yToPix(fvalues[k]);
// g.drawLine(x-5,y-5,x+5,y+5);
// g.drawLine(x-5,y+5,x+5,y-5);
g.fillOval(x-2,y-2,5,5);
}
}
}