import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.awt.Cursor.*; /** * Anzeige von Funktionsgraphen bis zu Funktionen fünften Grades * Dieses Programm kann Funktionsgraphen der Form: * f(x) = a*x^5 + b*x^4 + c*x^3 + d*x^2 + e*x + f anzeigen. * Die Koeffizienten können ganz einfach per Schiebebalken verändert und die * Auswirkung direkt auf der 'Leinwand' betrachtet werden. * @author ( (C) Thilo Beckmann ) * @version ( 15.12.2003 - 29.12.2003 ) */ public class funktionsgraph extends Applet implements AdjustmentListener, ActionListener { Leinwand L; /** siehe unten... */ Cursor meineMaus = new Cursor(0); public int s = 100; /** Divisor für Scrollbalken-Werte */ public double wert [] = new double [6]; /** Koeffizienten a,b,c,d,e und f */ public double wertalt [] = new double [6]; /** alte Koeffizienten a,b,c,d,e und f */ private int xmin=-1, xmax=1, ymin=-1, ymax=1; /** Definitionsbereich [xmin; xmax] und Wertebereich [ymin, ymax] */ Scrollbar scrollzoom = new Scrollbar (0, 10, 1, 1, 50), scroll [] = new Scrollbar [6]; /** Srcollbars zur Eingabe der Koeffizienten */ Label lab [] = new Label [10]; /** Labels, die den eingestellten Wert anzeigen */ Checkbox chkbox = new Checkbox ("auto. löschen",true); /** soll jeder Graph einzeln angezeigt werden? */ Checkbox f_anzeigen = new Checkbox ("f(x) anzeigen",true); /** soll die aktuelle Funktion angezeigt werden? */ Button loesche_alles = new Button ("komplett löschen"), /** soll die Zeichenfläche einmal komplett gelöscht werden */ werte_auf_null = new Button ("alle Werte auf Null"), /** alle Koeffizienten auf Null setzen */ ursprung = new Button ("Ursprung zentrieren"); /** Setzte den Ursprung wieder zurück in die Mitte */ /** Initialisierung der Anzeige, Buttons, Scrollbars und Label. * Die Anwendung läuft auf zwei verschiedenen Ebenen, die eine ist * die Anzeige der Funktion in einem Koordinatensystem ('Leinwand'). * Der Bereich mit allen Bedienelementen stellt die zweite Ebene dar. */ public void init(){ setCursor (meineMaus); Panel Bereich1 = new Panel(), Bereich2 = new Panel(); setBackground(Color.white); add (Bereich1); add (Bereich2); L = new Leinwand (Color.white); L.setSize (501,501); Bereich1.add(L); Bereich2.setLayout(new GridLayout (12,2,10,10)); /** die Scrollbalken bekommen je nach höhe des zugehörigen Exponenten * verschiedene Maximalwerte, damit die y-Werte nicht extrem über die * Größe der großten Integer hinauswachsen (hängt auch vom Sichtbereich * ab) */ scroll[0] = new Scrollbar (0,0, 1, -100, 101); // * x^5 scroll[1] = new Scrollbar (0,0, 1, -300, 301); // * x^4 scroll[2] = new Scrollbar (0,0, 1, -500, 501); // * x^3 scroll[3] = new Scrollbar (0,0, 1, -700, 701); // * x^2 scroll[4] = new Scrollbar (0,0, 1,-1000,1001); // * x^1 scroll[5] = new Scrollbar (0,0, 1,-5000,5001); // * x^0 for (int i=0; i<6; i++){ scroll[i].addAdjustmentListener (this); lab[i] = new Label (""+wert[i]+" * x ^ "+(5-i)); lab[i].setBackground(Color.white); Bereich2.add(scroll[i]); Bereich2.add(lab[i]); } lab[6] = new Label (""); lab[7] = new Label ("Zoom: "); lab[8] = new Label ("(c) Thilo Beckmann "); lab[8].setForeground(Color.blue); lab[9] = new Label ("24.12.2003"); lab[9].setForeground(Color.blue); Bereich2.add (chkbox); Bereich2.add (f_anzeigen); Bereich2.add (loesche_alles); loesche_alles.addActionListener(this); Bereich2.add (werte_auf_null); werte_auf_null.addActionListener(this); Bereich2.add (ursprung); ursprung.addActionListener (this); Bereich2.add (lab[6]); Bereich2.add (lab[7]); Bereich2.add (scrollzoom); scrollzoom.addAdjustmentListener(this); Bereich2.add (lab[8]); Bereich2.add (lab[9]); } /** Wenn ein Scrollbalken seinen Wert ändert/der Benutzer den Balkenwert * verändert, dann werden diese Veränderungen sofort übernommen und im * Graphen umgesetzt. */ public void adjustmentValueChanged (AdjustmentEvent e) { aktualisierenDerParameter(); zeichne(); } /** Wenn ein Button gedrückt wurde wird eine entsprechende Action durch- * geführt. Z.B. alle Scrollbalken zurück auf Null gesetzt */ public void actionPerformed (ActionEvent e) { String str=e.getActionCommand(); if (str=="komplett löschen") { } else if (str=="alle Werte auf Null") { for (int i=0; i<6; i++) { scroll[i].setValue(0); } aktualisierenDerParameter(); } else if (str=="Ursprung zentrieren") { L.aktualisiereVerschiebung(0.0,0.0); } L.fRect(Color.white,0,0,500,500); zeichne(); } /** Nur damit der Browswer, falls das Fenster mal verschoben wird oder * aus irgendwelchen anderen Gründen das Applet von anderen Fenstern ver- * deckt wird, den Graphen neuzeichnet. */ public void paint (Graphics g) { zeichne(); } /** Alle Werte von den Scrollbalken werden abgelesen und für die * Funktion verfügbar gemacht. */ private void aktualisierenDerParameter() { double altxmin, altxmax, altymin, altymax; boolean neuzeichnen=false; altxmin = xmin; altxmax = xmax; altymin = ymin; altymax = ymax; /** Mit einem Balken werden alle Maximalwerte bestimmt (ist über- * sichtlicher als für jeden Wert einen eingene Scrollbalken zu * benutzen) */ xmin = scrollzoom.getValue() * -1; xmax = scrollzoom.getValue() * 1; ymin = scrollzoom.getValue() * -1; ymax = scrollzoom.getValue() * 1; if (xmin == altxmin && xmax == altxmax && ymin == altymin && ymax == altymax) { } else { L.fRect(Color.white,0,0,500,500); zeichne(); } for (int i=0; i<6; i++) { wertalt[i] = wert[i]; wert[i] = scroll[i].getValue(); lab[i].setText (""+(wert[i]/s)+" * x ^ "+(5-i)); } } /** Die Parameter der Funktion werden an die 'Leinwand' übergeben und * der Auftrag zum Zeichnen der Funktion erteilt. */ public void zeichne() { for (int i=0; i<6; i++) { L.werteAktualisieren(i,wert[i],wertalt[i]); } L.zoomAktualisieren(scrollzoom.getValue()); L.zeichne(chkbox.getState(), f_anzeigen.getState()); } } /** *********************************************************************** * eine Klasse die, die Anzeige des Graphen übernimmt * und in das Layout eingefügt werden kann. * *********************************************************************** */ class Leinwand extends Canvas implements MouseMotionListener { Graphics g; Cursor zeiger = new Cursor(13); private int xmousealt=-1, ymousealt=-1, xmouse, ymouse; private double xverschiebung=0, yverschiebung=0; private int zoomfaktor=10; private int xmitte, ymitte; private int xminp = 0, xmaxp = 499, yminp = 0, ymaxp = 499; /** Pixelgröße des Bildschirms */ private int s = 100; /** Divisor für Scrollbalken-Werte */ private int pixelschritte = 3; /** Genauikeit des Graphen; bei 1 höchste G. */ private double wert [] = new double [6]; /** Koeffizienten a,b,c,d,e und f */ private double wertalt [] = new double [6]; /** alte Koeffizienten a,b,c,d,e und f */ private double xmin=-10, xmax=10, ymin=-10, ymax=10;/** Definitionsbereich [xmin; xmax] und Wertebereich [ymin, ymax] */ public double f (double x, double a, double b, double c, double d, double e, double f) {return a*x*x*x*x*x + b*x*x*x*x + c*x*x*x + d*x*x + e*x + f;} /** Der Constructor für die Leinwand */ public Leinwand (Color bgcolor) { setBackground (bgcolor); addMouseMotionListener(this); } /** Zum Löschen der gesammten Feldes (auch von einer übergeordneten Klasse aus) */ public void fRect (Color farbe, int xp1,int yp1,int xp2, int yp2) { g = getGraphics(); g.setColor (farbe); g.fillRect (xp1,yp1,xp2,yp2); } /** Zum Markieren mit der Maus */ public void mouseDragged (MouseEvent e) { int x=e.getX(); int y=e.getY(); double xfaktor, yfaktor; if (xmousealt == -1 | ymousealt == -1) { xmouse = x; ymouse = y; } else { xmouse = x; ymouse = y; xfaktor = (xmax-xmin) / ((double)xmaxp); yfaktor = (ymax-ymin) / ((double)ymaxp); xverschiebung = xverschiebung + ((double)(xmousealt - xmouse)* xfaktor); yverschiebung = yverschiebung + ((double)(ymousealt - ymouse)* yfaktor); xmin = -(double)zoomfaktor + xverschiebung; xmax = (double)zoomfaktor + xverschiebung; ymin = -(double)zoomfaktor - yverschiebung; ymax = (double)zoomfaktor - yverschiebung; g.setColor (Color.white); g.fillRect (1,1,499,499); zeichne(true,true); } xmousealt = xmouse; ymousealt = ymouse; /** Markierer (zum Markieren von Abschnitten o.Ä.) * g.setColor (Color.pink); * g.fillRect (x,y,3,3); */ } /** Setzt den Start x- und y-Wert zurück, sonst würde der Graph immer * verschoben, wenn die Maus bewegt würde. */ public void mouseMoved (MouseEvent e) { setCursor(zeiger); xmousealt = -1; ymousealt = -1; } /** Die Werte aus der Klasse funktionsgraph werden übernommen, um den Graphen * mit allen eingestellten Parametern zeichnen zu können. */ public void werteAktualisieren (int wertindex, double werte, double wertealt) { wert[wertindex] = werte; wertalt[wertindex] = wertealt; } /** Die Größe des Koordinatensystems wird ebenfalls aus den Einstellungen * der Scrollbalken entnommen und über die Klasse funktionsgraph bestimmt */ public void zoomAktualisieren (int zoom) { zoomfaktor = zoom; xmin = -(double)zoomfaktor + xverschiebung; xmax = (double)zoomfaktor + xverschiebung; ymin = -(double)zoomfaktor - yverschiebung; ymax = (double)zoomfaktor - yverschiebung; } public void aktualisiereVerschiebung (double xver, double yver) { xverschiebung = xver; yverschiebung = yver; zeichne(true, true); } /** Steuermethode zum Zeichnen des Graphen (wird von funktionsgraph auf- * gerufen) */ public void zeichne(boolean boolloeschen, boolean boolanzeigen) { boolean loeschen = boolloeschen; boolean anzeigen = boolanzeigen; if (loeschen) { loesche_graph(Color.white); } else if (! loeschen) { loesche_graph(Color.lightGray); } zeichne_xachse(); zeichne_yachse(); zeichne_graph(); g.setColor (Color.black); g.drawRect (0,0,500,500); if (anzeigen) { zeichne_funktionAlsText(); } } /** Die eingestellte Funktion wird als Text im oberen Teil der Anzeige * ausgegeben und kann so vom Benutzer übersichtlich abgelesen werden */ public void zeichne_funktionAlsText () { String funktion="f(x) = "; boolean mit_plus = false; if (wert[0] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[0]/s) + " * x ^ 5 "; mit_plus = true; } if (wert[1] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[1]/s) + " * x ^ 4 "; mit_plus = true; } if (wert[2] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[2]/s) + " * x ^ 3 "; mit_plus = true; } if (wert[3] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[3]/s) + " * x ^ 2 "; mit_plus = true; } if (wert[4] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[4]/s) + " * x "; mit_plus = true; } if (wert[5] != 0) { funktion = funktion + pluszeichen(mit_plus) + (wert[5]/s) + ""; mit_plus = true; } if (!mit_plus) { funktion = funktion + "0"; } g.setColor (Color.lightGray); g.fillRect (1, 1, 499, 20); g.setColor (Color.black); g.drawString (funktion, 10,15); } /** für methode: zeichne_funktionAlsText */ public String pluszeichen (boolean mit_plus) { if (mit_plus) { return " + "; } else { return ""; } } /** Für eine Stelle x wird die Pixelabzisse bestimmt */ private int xpixel(double x){ double a = ((double)xmaxp)/(xmax - xmin); double b = -a * xmin; int pixelstelle = (int)(a*x+b+0.5); return pixelstelle; } /** Für einen Wert y wird die Pixelordinate bestimmt */ private int ypixel(double y) { double c = -((double)ymaxp)/(ymax - ymin); double d = -c * ymax; int pixelwert = (int)( c * y + d + 0.5); return pixelwert; } /** Für eine Pixelabzisse n wird die Stelle des Definitionsbereichs bestimmt */ private double stelle(int n){ double x = ((xmax - xmin)/(double)(xmaxp+1)) *(double)n + xmin; return x; } /** Es wird eine x-Achse gezeichnet und für den vorgegebenen Definitionsbereich skaliert */ public void zeichne_xachse(){ int wertp = ypixel (0.0); g.setColor (Color.black); g.drawLine (0,wertp, xmaxp, wertp); int stelle = (int)(xmin); int stellep = xpixel(stelle); while (stelle <= (int)(xmax)) { g.drawLine (stellep, wertp+2, stellep, wertp-2); if (stelle != 0) { g.drawString(Integer.toString(stelle), stellep-2, wertp+20); } if ( (int)((xmax-xmin)/11) > 0 ) { stelle = stelle + (int)( (xmax-xmin)/11 ); } else { stelle++; } stellep = xpixel(stelle); } } /** Es wird eine y-Achse gezeichnet und für den vorgegebenen Wertebereich skaliert */ public void zeichne_yachse() { int stellep = xpixel (0.0); g.setColor (Color.black); g.drawLine(stellep, 0,stellep, ymaxp); int wert = (int)(ymin); int wertp = ypixel(wert); while (wert <= (int)(ymax)) { g.drawLine(stellep-2, wertp, stellep+2, wertp); if (wert != 0) { g.drawString(Integer.toString(wert), stellep + 5, wertp + 5); } if ( (int)((ymax-ymin)/11) > 0 ) { wert = wert + (int)( (ymax-ymin)/11 ); } else { wert++; } wertp = ypixel(wert); } } /** Der Graph einer Funktion f(x) wird über dem vorgegebenen Definitionsbereich * gezeichnet */ public void zeichne_graph() { double x, y; int p1, p2=0, n2=0; for (int n1=0; n1<500; n1=n1+pixelschritte) { x = stelle(n1); y = f(x,wert[0]/s,wert[1]/s,wert[2]/s,wert[3]/s,wert[4]/s,wert[5]/s); p1 = ypixel(y); if (n1 > 0) { g.setColor (Color.blue); g.drawLine (n1,p1,n2,p2); } p2=p1; n2=n1; } } /** Der alte Graph einer Funktion f(x) wird über dem vorgegebenen * Definitionsbereich geloescht, dadurch muss nicht der gesamte * Bereich neugezeichnet werden (Blinkeffekt wird verhindert) */ public void loesche_graph(Color col) { double x, y; int p1, p2=0, n2=0; for (int n1=0; n1<500; n1=n1+pixelschritte) { x = stelle(n1); y = f(x,wertalt[0]/s,wertalt[1]/s,wertalt[2]/s,wertalt[3]/s,wertalt[4]/s,wertalt[5]/s); p1 = ypixel(y); if (n1 > 0) { g.setColor (col); g.drawLine (n1,p1,n2,p2); } p2=p1; n2=n1; } } }