# Funktionsplotter



## Underworld (18. Okt 2009)

Hi ihr Javaspezialisten,
ich habe seit diesem Jahr Informatik Grundkurs und habe vorher noch nie Programmiert, jedoch macht mir Java unendlich viel Spaß und ich versuche momentan einen kleinen Funktionsplotter zuschreiben.
Das Koordinatenystem habe ich mitlerweile schon ganz gut hinbekommen und einige Ansätze eine Funktion zu zeichnen hatte ich auch schon 

Mein Grafikfenster ist übrigens 1000*1000 Pixel groß und den Mittelpunkt habe ich bei 500/500 gewählt und eine Längeneinheit entspricht bei mir 50 Pixel

Also zu meinen Versuchen Funktionen darzustelllen.

1. Variante:
for (int i = 0; i <= 1000; i += 1) {
g.drawLine(500 + 7 * i, 500 - (i * i), 500 + 7 * (i + 1),500 - ((i + 1) * (i + 1)));
		}

hier habe ich mir gedacht, ich könnte doch einfach von jedem Punkt zum nächsten Punkt einfach eine Linie ziehen und so die Funktion plotten.
Dummerweise habe ich, weil ich ja als LE 50 Pixel gewählt habe, wenn ich keinen "Zerrungsfaktor" wähle, eine x² Funktion die einfach unglaublich dünn ist. Deswegen habe ich beim x-Wert einfach Wurzel(50) als Zerrungsfaktor gewählt.
Das gibt mir zwar eine x² Funktion raus, alle anderen Funktionstypen, wie lineare Funktionen oder höhergradige Funktionen lassen sich damit aber nicht zeichnen

2. Variante:
for (int i = 0; i <= 1000; i++) {
g.drawRect(500 + 7*i, 500 - i*i, 0, 0);
		}

Hier habe ich versucht die Funktion mit Punkten zu beschreiben. Leider lässt sich das auch nicht wirklich realisieren.

In dem Fall habe ich eine x² Funktion, aber eben nur mit Punkten dargestellt...
Aber wieder genau das gleiche Problem, dass hier nur x² Funktionen gezeichnet werden können!

Leider habe ich noch nicht viel mehr Befehle für Java kennengelernt und ich habe auch keine neuen Ideen wie ich das Problem angehen könnte!

Ich würde mich über ein paar neuen "Ideen oder Denkanstöße" freuen. Einen fertigen Code für einen Funktionsplotter will ich nicht, da würde ich meiner Meinung nach auch nicht viel lernen

lg Flo


----------



## Marco13 (18. Okt 2009)

OK, da kann man auf unterschiedlichSTen Ebenen ansetzen. Man kann einfach ein Koordinatensystem von 0,0 bis 1000,1000 definieren und dort "irgendwo" mit g.drawLine ein paar Linien reinmalen. Das funktioniert dann vielleicht so weit, wie man das wollte, und man macht sich an's nächste Programm. 

Oder man macht es flexibler.

Eine Funktion "f(x)" könnte man z.B. beschreiben durch ein 

```
interface Function
{
    float evaluate(float x);
}
```
Das würde man dann z.B. mit der Wurzelfunktion implementieren

```
class SquareRootFunction implements Function
{
    public float evaluate(float x)
    {
        return (float)Math.sqrt(x);
    }
}
```
So weit, dass bei diesem Plotter auch der hier offensichtlich kritische Fall von x<0 berücksichtigt wird, gehe ich jetzt mal nicht.....

Das kann aber beliebig verallgemeinert werden, z.B. so dass man dann sowas machen kann wie

```
plotter.plot(new GeneralFunction("x*x+Math.log(x+Math.sqrt(x))");
```
aber das wäre "advanced" - mit dem Interface hält man sich diese Option aber auf die einfachste denkbare Weise offen.


So ein Funktionsplotter kann entweder ganz einfach Werte von -500 bis +500 plotten können. Dann muss man seine Funktion halt passend wählen. Mein Bildschirm ist übrigens nur 800 Pixel hoch *wink*

Oder man macht es flexibler. 

Was will man plotten können. (Alles! Klar  aber... ) in erster Linie will man ja ein Rechteck auf ein anderes abbilden. Das Rechteck, das die Funktion einnimmt, soll irgendwie in das Rechteck gepresst werden, das sich "Fenster" nennt. Die Abmessungen des Fensters (bzw. des JPanels, auf das du vermutlich zeichnen wirst) sind immer klar und immer gleich: Oben links (0,0) bis unten rechts (panel.getWidth(), panel.getHeight()). Fragt sich, wie "groß" die Funktion ist. Zumindest will der Benutzer den minimalen und den maximalen x-Wert eingeben, in dem die Funktion berechnet werden soll. Den minimalen und maximalen y-Wert KÖNNTE man ausrechnen - sofern er nicht sowas wie f(x) = 1/x plotten will, und als minimalen x-Wert 0 angibt. Also gibt's für den min/max-y-Wert die Optionen "eingeben lassen" oder "ausrechnen" - ersteres ist erstmal einfacher. Man könnte also sowas machen:

```
class Plotter
{
    void setRangeX(float minX, float maxX) { ... }
    void setRangeY(float minY, float maxY) { ... }
}
```
oder 

```
class Plotter
{
    void setMinX(float minX) { ... }
    void setMaxX(float maxX) { ... }
    ....
}
```
... das musst du dir überlegen.

Wenn man diese Werte dann hat, kommt der Teil, der für dich vermutlich der Hauptanlass für die Frage war: Wie kommt die Funktion ins Fenster? Im Prinzip mit einem Dreisatz. Ein bißchen halb-pseudo-code:

```
// Pixelweise über die ganze Fensterbreite laufen
for (int xScreen=0; xScreen<getWidth(); xScreeen++)
{
    // Relative position im Fenster ausrechnen - also die x-Position
    // im Fenster als einen Wert zwischen 0 und 1 darstellen
    float relativeX = (float)xScreen / getWidth();

    // Entsprechende Position im zu zeichnenden Intervall ausrechnen:
    // Wenn man den Bereich von x=1.0 bis x=3.0 in ein Fenster
    // zeichnen will, das 100 Pixel breit ist, und man gerade beim 
    // Pixel 50 (also an der relativen Position 0.5) ist, dann ist das,
    // auf das Intervall umgerechnet, gerade die Position
    // minX + (maxX-minX) * relativeX =
    // 1.0 + (3.0 - 1.0) * 0.5 = [b]2.0[/b] - passt....
    float xWorld = minX + (maxX-minX) * relativeX;

    // Die Funktion an dieser Stelle auswerten
    float yWorld = function.evaluate(xWorld);
  
    // Den y-Wert in die entsprechende Fensterposition umprechnen
    // (das ist quasi das "umgekehrte" zur Berechnung von xWorld)
    float relativeY = (maxY - minY) / (yWorld - minY);
    int yScreen = (int)(relativeY * getHeight());
    
    // Linie zeichnen:
    g.drawLine(...., xWorld, yWorld);
}
```
Ist nur ungetestet hingeschrieben, aber so grob... Natürlich muss man die Linie immer zwischen dem aktuellen (xWorld,yWorld) und dem vorigen zeichnen, und im Allgemeinen sollte man in der paintComponent NICHT rechnen, sondern NUR zeichnen, d.h. statt des "drawLine" würde man die Ergebnisse ggf. nur in einen Array legen, und DEN dann in der paintComponent zeichnen, aber das kann man ggf. noch anpassen...

Vielleicht ist dir (und hoffentlich angenehm) aufgefallen, dass na nirgendwo Werte wie 1000, 700, 500 oder irgendwelche "hartverdrahteten" Funktionen drin vorkommen. Er plottet "irgendwas", in der allgemeinsten Form die (wenn man nicht noch mehr Aufwand reinstecken will) möglich ist. Im Idealfall könnte man dann irgendwann sowas sagen wie

```
plotter.setRangeX(-3,4);
plotter.setRangeY(-2,6);
plotter.plot(new SquareFunction());
```
machen, um die Funktion f(x)=x*x im Bereich -3 bis 4 in ein Fenster zu zeichnen - und dabei ist egal, wie groß das Fenster ist: Es wird dieser Bereich der Funktion dargestellt.

Soweit erstmal...


----------



## 0x7F800000 (18. Okt 2009)

```

```
:toll: (sorry für OT )


----------



## Underworld (18. Okt 2009)

Hey Marco13,
vielen, vielen Dank für deine tolle Antwort! Find ich super, dass du dir soviel Zeit nimmst!

Habe heute leider keine Zeit mehr, mich damit zu beschäftigen, werde mich aber morgen daran setzen!

lg und gn8 Flo

Edit: Konnte es nicht lasssen und habs schon mal langsam durchgelesen. Es sind zwar noch ein paar unbekannte Begriffe drinnen, aber das les ich mir morgen dann an!
Klingt auf jeden Fall spannend, vor allem weil das alles so variabel gelöst ist!


----------



## Underworld (19. Okt 2009)

Hi,
jetzt habe ich Zeit mich damit zu beschäftigen ^^

Ein paar Fragen:

1. Interfaces
Ich hab zwar noch nicht wirklich Ahnung, was ein Interface genau macht. Sie sind doch eigentlich auch eine Klasse, was ist da der unterschied?
Immerhin hab ich schon mal herausgefungen wie ich es einrichte, so dass es fuktioniert!

2. zu Class Plotter
Ich nehme an das ist ein Konstruktor?
Sieht dann also so aus:

```
class Plotter {
	float minX, maxX, minY, maxY;

	public void setRangeX(float minX, float maxX) {
		this.minX = minX;
		this.maxX = maxX;
	}

	public void setRangeY(float minY, float maxY) {
		this.minY = minY;
		this.maxY = maxY;
	}
}
```
Kann ich das auch so schreiben:

```
class Plotter {
	float minX, maxX, minY, maxY;

	public void setRange(float minX, float maxX) {
		this.minX = minX;
		this.maxX = maxX;

		this.minY = minY;
		this.maxY = maxY;
	}
}
```
Müsste ich bis jetzt aber soweit verstandenhaben , weiter gehts 


3. Edit: Sorry, hab auf Antworten statt auf Vorschau geklickt. Weitere Fragen kommen gleich noch *g*

3. Edit: Ich spiel jetzt mal am Code rum. Ich denke ich werde mich später nochmal wegen Fragen melden :toll:

4. Frage entdeckt!

Bei dieser Schleife: 
	
	
	
	





```
for (int xScreen=0; xScreen<getWidth(); xScreeen++)
```

Für was steht getWidth() Das habe ich doch nirgendswo definiert?


----------



## Marco13 (19. Okt 2009)

_Ich hab zwar noch nicht wirklich Ahnung, was ein Interface genau macht. Sie sind doch eigentlich auch eine Klasse, was ist da der unterschied?_

In einem Interface steht nur, welche Methoden eine Klasse (die das Interface implementiert) anbieten muss. In diesem Fall hat das halt den Vorteil, dass der Plotter nur _rigendeine_ "Function" kennt, und man zur Laufzeit austauschen kann, was "Function" denn nun im Moment sein soll.


_
Ich nehme an das ist ein Konstruktor?
_
Nee, nur sowas wie ein "setter" - einfach ein Methode, um (private) Variablen zu setzen.
_
Kann ich das auch so schreiben:
_
Mit 
[c]public void setRange(float minX, float maxX*, float minY, float maxY*) {[/c]
würd's gehen - aber immer berücksichtigen, dass man das für X und Y u.U. unabhängig voneinander setzen will - vielleicht soll es für Y ja automatisch ausgerechnet werden, da wäre es ungünstig, wenn man bei jedem Ändern des X-Ranges auch "irgendwelche" Werte für Y übergeben müsste...

_
Bei dieser Schleife: 
	
	
	
	






		Java:In die Zwischenablage kopieren


for (int xScreen=0; xScreen<getWidth(); xScreeen++)/JAVA]

Für was steht getWidth() Das habe ich doch nirgendswo definiert?[/i]

Das ist das getWidth() von dem JPanel, in das du zeichnest.

_


----------



## Leroy42 (19. Okt 2009)

Ein Konstruktor wäre dann beispielsweise


```
public Plotter(float minX, float maxX, float minY, float maxY) {
  setRangeX(minX, maxX) ;
  setRangeY(minY, maxY) ;
}
```


----------



## Underworld (19. Okt 2009)

Nochmal zum getWidth() Befehl


```
for (int xScreen = 0; xScreen < getWidth() ; xScreen++)
```

Da steht bei mir leider: Cannot find symbol - method getWidth
Es kann aber auch sein, dass es das nicht findet, weil ich eine vorgefertigte "Grafikfenster"Klasse von meinem Grundkurslehrer benutze 


Hm, bei
          g.drawLine(...,(int) xWorld , (int) yWorld);
Was muss ich denn da für Anfangswerte wählen?
Ich komm einfach nicht dahinter ???:L


----------



## Marco13 (19. Okt 2009)

Ohje - "Grafikfenster Klasse" - solche Sachen sind vielleicht meistens gut gemeint, und sollen den Leuten den Einstieg erleichtern - allerdings tritt dabei das Problem auf, dass sich irgendein Pfatzke diese Klasse aus den Rippen geleiert hat, und im ganzen Internet kein Mensch eine Frage dazu beantworten kann ... sofern die Klasse nicht komplett gepostet wird (und selbst dann finde ich es nicht so... besonders.. die zu verwenden - aber wenn man dazu genötigt wird.. naja).

Dieses "Grafikfenster" wird sicher eine Methode haben, um die Breite (in Pixeln) zu bestimmen. Vermutlich heißt sich "getBreite" oder so :autsch:

Bei dem g.drawLine -  ich seh' grad' dass da xWorld/yWorld stand - das müßte natürlich xScreen und yScreen sein. Und sonst ...ja, das hatte ich ja erwähnt: Man muss immer zwei aufeinanderfolgende Punkte kennen. Da kann man sich was geschicktes überlegen... für den Anfang könntest du erstmal sowas machen wie

```
int prevX = 0;
int prevY = 0;

// Pixelweise über die ganze Fensterbreite laufen
for (int xScreen=0; xScreen<getWidth(); xScreeen++)
{
     ... wie vorher...    
  
    // Linie zeichnen:
    if (xScreen > 0)
    {
        g.drawLine(prevX, prevY, xScreen, yScreen);
    }
    prevX = xScreen;
    prevY = yScreen;
}
```


----------



## Underworld (19. Okt 2009)

Hi,
ja, das hab ich mir auch schon gedacht. Nur weiß ich leider nicht, woher ich ein Grafikfenster bekomme und wie ich es richtig verbinde mit ner anderen Klasse. 

Das mit der getWidth() hab ich leider noch nicht ganz gelöst, ich denke ich werde einfach vorerst einfach den Wert 1000 hinschreiben, den ich ja auch benutze!

Das mit den 2 Aufeinanderfolgenden Werten hab ich mir auch gedacht, jedoch bin ich nicht auf diese kleine, aber geschickte Umwandlung gekommen... Hab so ziemlich alle Möglichen Kombinationen durchprobiert^^

Hier ist momentan mein Code, leider funktioniert noch nicht alles so, wie ich das will


```
import java.awt.*;
import javax.swing.*;

class test implements Function {
	float yWorld;
	float relativeX;
	float minX;
	float maxY;
	float maxX;
	float minY;
	int prevX = 0;
	int prevY = 0;

	//    // Da komm ich leider nicht ganz so klar mit ^^ Hab einfach keine Ahnung wie ich Setter benutzen sol
	//       void setMinX(float minX) {  }
	//     void setMaxX(float maxX) {} 
	//     void setMinY(float minY) {}
	//     void setMaxY(float maxY) {}

	public float evaluate(float x) {
		return (float) x * x;
	}

	public void plotten() {
		Graphics2D g = GrafikFenster.gibGrafikFläche();
		
		minX = -10;
		maxX = 10;
		minY = -10;
		maxY = 10;

		for (int xScreen = 0; xScreen < 1000; xScreen += 1) {
			float relativeX = (float) xScreen / 1000;
			float xWorld = minX + (maxX - minX) * relativeX;
			float yWorld = evaluate(xWorld);
			float relativeY = (maxY - minY) / (yWorld - minY);
			int yScreen = (int) (relativeY * 1000);
			if (xScreen > 0) {
				g.drawLine(prevX, prevY, xScreen, yScreen);
			}
			prevX = xScreen;
			prevY = yScreen;

		}
	}
}
```

und in der "Subklasse"/"Interfaceklasse" (hab keine Ahnung wie man das nennt)
hab ich ganz simpel nur das drinnstehen

```
interface Function
{
    float evaluate(float x);
}
```

Kann ich das Interface nicht auch in die Klasse "test" noch irgendwie reinschreiben?


----------



## Marco13 (19. Okt 2009)

Was bietet "GrafikFenster" denn so für Methoden an? Kannst du die Klasse hier posten? (Der Verwendung nach ist die mit an Sicherheit grenzender Wahrscheinlichkeit oberster Murks, aber ... mal sehen...)

Das mit dem interface Function / implements Function war .. nicht ganz so gemeint... aber geht... das kann man dann noch anpassen. 

Du müßtest aber etwas genauer beschreiben, was nicht funktioniert. (Am besten compilierbaren Code posten, damit man's schnell und einfach selbst testen und nachvollziehen kann).

BTW: Es bietet sich an, Variablen immer mit einem möglichst kleinen Gültigkeitsbereich zu definieren. Also nicht

```
void something()
{
    [b]float x = 0;[/b]

    // Viel code, der x nicht verwendet...
    // Viel code, der x nicht verwendet...
    // Viel code, der x nicht verwendet...

    for (int i=0; i<10; i++)
    {
        x = berechne(i);
        System.out.println(x);
    }
}
```
sondern

```
void something()
{
    // Viel code, der x nicht verwendet...
    // Viel code, der x nicht verwendet...
    // Viel code, der x nicht verwendet...

    for (int i=0; i<10; i++)
    {
        [b]float x = [/b]berechne(i);
        System.out.println(x);
    }
}
```



Insbesondere sollten die Instanzvariablen (also die, die oben in der Klasse stehen) NUR die sein, die man _unbedingt_ dort braucht (d.h. vier von denen, die da im Moment stehen, sind überflüssig)


----------



## Underworld (20. Okt 2009)

Das ist die Klasse GrafikFenster


```
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;

/**
 * Class GrafikFenster - Eine Klasse, die einfache grafische Zeichnungen 
 * in einem Programmfenster ermöglicht.

 */

public class GrafikFenster
{
    private JFrame frame;
    private CanvasPane canvas;
    private static Graphics2D graphic;
    private Color backgroundColor;
    private Image canvasImage;
    private int wWidth,wHeight;
    
    private static GrafikFenster singleton;

    /**
     * Erzeugt eine Grafikfenster mit Standardmaßen 600*500 und Hintergrundfarbe weiß 
     * @param titel  Titel des Fensters     
     */
    public GrafikFenster(String titel)
    {
        this(titel, 1000, 1000, Color.white);        
    }

    /**
     * Erzeugt ein Grafikfenster mit weißem Hintergrund.
     * @param titel  Fensterueberschirft
     * @param breite  Breite des Fensters
     * @param hoehe  Hoehe des Fensters
     */
    public GrafikFenster(String titel, int breite, int hoehe)
    {
        this(titel, breite, hoehe, Color.white);
    }

    /**
     * Erzeugt ein Grafikfenster.
     * @param titel  Fensterueberschirft
     * @param breite  Breite des Fensters
     * @param hoehe  Hoehe des Fensters
     * @param hintergrundFarbe  Hintergrundfarbe des Zeichenfensters
     */
    private GrafikFenster(String titel, int breite, int hoehe, Color hintergrundFarbe)
    {
        wWidth=breite;
        wHeight=hoehe;
        frame = new JFrame();
        canvas = new CanvasPane();
        canvas.setPreferredSize(new Dimension(breite, hoehe));
        frame.getContentPane().add(canvas,BorderLayout.CENTER);
        
        frame.setTitle(titel);
        backgroundColor = hintergrundFarbe;
        frame.pack();
        zeige();
    }
    
    public void zeige()
    {
        if(graphic == null) {
            // nur beim ersten Aufruf wird der Hintergrund mit der Hintergrundfarbe 
            // gefuellt
            Dimension size = canvas.getSize();
            canvasImage = canvas.createImage(size.width, size.height);
            graphic = (Graphics2D)canvasImage.getGraphics();
            graphic.setColor(backgroundColor);
            graphic.fillRect(0, 0, size.width, size.height);
            graphic.setColor(Color.black);
        }
        frame.setVisible(true);
    }

    public static GrafikFenster gibFenster()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return singleton;
    }
    
    public static void aktualisiereGrafik()
    {
        gibFenster().frame.repaint();
    }
    
    public static Graphics2D gibGrafikFläche()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return graphic;
    }
    
     private class CanvasPane extends JPanel
    {
    
        
        public void paint(Graphics g)
        {
            g.drawImage(canvasImage, 0, 0, null);
        }
        
        public int getWidth() {
            return wWidth;
        }
        
        public int getHeight() {
            return wHeight;
        }
    }
    
}
```



Der Code den ich geschickt habe, müsste Kompilierbar sein, zumindest zeigt er bei mir keine Fehlermeldung an. 

Das Problem ist momentan, dass zwar ein Graph gezeichnet wird, der jedoch rein gar nichts mehr der x² Funktion zu tun hat.


----------



## Marco13 (20. Okt 2009)

Oh ja, die Zeile für relativeY müßte
float relativeY = (yWorld - minY) / (maxY - minY);
heißen ... (hättest du vielleicht mal nachvollziehen sollen :bae:  )

Beachte aber auch, dass beim Zeichenfenster der Punkt (0,0) ganz oben ist - du wirst den Plot ggf. durch
int yScreen = *getHeight()-*(int) (relativeY * getHeight());
umdrehen müssen (EDIT: zu getHeight() steht unten noch was)

Die GrafikFenster-Klasse macht nicht so schlimme Sachen, wie ich dachte, aber ... Sachen, die auf andere Art schlimm sind (es kann z.B. nie zwei solche Fenster geben... und so). Also, ich halte von solchen Pseudo-Hilfs-Klassen nicht so viel, aber ... wie auch immer. Du kannst dort ggf. noch die Methoden

```
public static int gibBreite()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return singleton.canvas.getWidth();
    }
    public static int gibHoehe()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return singleton.canvas.getHeight();
    }
```
einfügen, damit du statt der 1000 jeweils sowas machen kannst wie

```
int width = GrafikFenster.gibBreite();
for (int xScreen = 0; xScreen < width; xScreen += 1) { ...
```


----------



## Underworld (20. Okt 2009)

Guten morgen
(jeah, hab heut und morgen schulfrei ^^)

Hab gerade in diesem Moment den Code so hingeschrieben, dass es funktioniert!

jetzt muss ich den Code nur noch nen bisschen verschönern und mein Koordinatensystem drüber ziehen, was ich schon programmiert habe *g*

Edit:
nächstes Problem, ich hab zwar verstanden was hier passiert:

```
public float evaluate(float x) {
		return (float) (x * x + x);
	}
```

Jedoch weiß ich nicht, was (x*x + x) für einen Wert hat.
Ist das ein String? Mein Ziel ist, über einen Konstruktor von außen die Funktion festzusetzen.
Dieser Term scheint aber kein String Wert zu sein, wie setze ich ihn den fest?

Edit2: Ist das ein boolean? Ach, ich tests einfach mal aus 

Edit3: Habs ausprobiert, jedoch ist das ein float Wert.
Ich habe bisher gedacht ein "float" ist eine Zahl. Naja, jetzt muss ich noch versuchen, das irgendwie in einen Konstruktor zu bekommen. Schaff ich schon


----------



## Marco13 (20. Okt 2009)

Ähm ... was hast du gerade mit dem armen x vor? ???:L


----------



## Underworld (20. Okt 2009)

Marco13 hat gesagt.:


> Ähm ... was hast du gerade mit dem armen x vor? ???:L



Ich probier grad ein paar Sachen aus, ich glaub ich bau aber nur Schrott :autsch:

Mein Ziel ist, dass ich die Funktion von außen angeben kann.

Ich hab aber keine Ahnung wie ich den Term hier drinn besschreiben soll:

return (float) (x * x + x);

so gehts ja nicht

```
String test1;     
public void test(float test1)
{
this.test1=test1;

}

    public float evaluate(float x) {
     test();
        return (float) (test1);
    }
```

Aber das sieht sogar für mich komplettt falsch aus :autsch:


----------



## Landei (20. Okt 2009)

Underworld hat gesagt.:


> komplettt falsch


:-D


----------



## Marco13 (20. Okt 2009)

Ja, das meinte ich oben als ich sagte, dass das mit dem Interface etwas anders gemeint war.

```
class Plotter
{
    private Function function = null;

    public void setFunction(Function f)
    {
        this.function = f;
    }

    public void plotten()
    {
        if (function == null) return; // oder so...

        // In der Schleife dann
        float yWorld = function.evaluate(xWorld);

         ....
}
```

und dann von außen die Funktion setzen, z.B. so

```
Function function = new Function()
{
    public float evaluate(float x)
    {
        return 2*x+3;
    }
});
plotter.setFunction(function);
```


----------



## Underworld (21. Okt 2009)

Hi,

hab mir den Code jetzt angeschaut und hab noch folgendes Problem
Interface code:

```
interface Function{

Function function = new Function()
{
    public float evaluate(float x)
    {
        return 2*x+3;
    }
};

Plotter.setFunction(function);
}
```


Bei Plotter.setFunction(function); kommt immer der Fehler 
<identifier> expected

mein, plotter code sieht mom so aus:


```
import java.awt.*;
import javax.swing.*;

class Plotter implements  Function {
   
private Function function = null;
 
    public void setFunction(Function f)
    {
        this.function = f;
    }



    private void Koordinatensystem() {

        // Standard-Grafikoberfläche holen:
        Graphics2D g = GrafikFenster.gibGrafikFläche();

        // Koordinatensystem

        // Koordinatengitter
        g.setColor(new Color(211, 211, 211));
        for (int a = 25; a <= 1000; a += 25) {
            g.drawLine(a, 0, a, 1000);
        }
        for (int a = 25; a <= 1000; a += 25) {
            g.drawLine(0, a, 1000, a);
        }
        g.setColor(Color.BLACK);

        // Achsen
        g.drawLine(500, 0, 500, 1000);
        g.drawLine(0, 500, 1000, 500);
        // Kleine Striche an den Achsen
        for (int a = 0; a <= 1000; a += 50) {
            g.drawLine(a, 504, a, 496);
            g.drawLine(504, a, 496, a);
        }
        for (int a = 25; a <= 1000; a += 50) {
            g.drawLine(a, 502, a, 498);
            g.drawLine(502, a, 498, a);
        }

        // Koordinatenzahlen schreiben
        g.drawString("0", 485, 515);
        // Rechts von y-Achse
        for (int a = 1; a <= 10; a++) {
            g.drawString(String.valueOf(a), 50 * a + 497, 518);
        }
        // Links von y-Achse
        for (int a = 1; a <= 10; a++) {
            g.drawString(String.valueOf(-a), -1 * 50 * a + 494, 518);
        }
        // Oberhalb von x-Achse
        for (int a = 1; a <= 10; a++) {
            g.drawString(String.valueOf(a), 480, 500 - 50 * a);
        }

        // Unterhalb von x-Achse
        for (int a = 1; a <= 10; a++) {
            g.drawString(String.valueOf(-a), 480, 500 + 50 * a);
        }

    }

    public void FunktionsPlotter() {
        
         if (function == null) return;
         
        Graphics2D g = GrafikFenster.gibGrafikFläche();
        Koordinatensystem();
        // Breite und Höhe definieren, durch GrafikFenster
        int width = GrafikFenster.gibBreite();
        int height = GrafikFenster.gibHoehe();

        float minX, maxX, minY, maxY;

        int prevX = 0;
        int prevY = 0;

        minX = -10;
        maxX = 10;
        minY = -10;
        maxY = 10;

        for (int xScreen = 0; xScreen < width; xScreen += 1) {
            float relativeX = (float) xScreen / width;
            float xWorld = minX + (maxX - minX) * relativeX;
            float yWorld = Function.evaluate(xWorld);
            float relativeY = (yWorld - minY) / (maxY - minY);
            int yScreen = height - (int) (relativeY * height);
            if (xScreen > 0) {
                g.drawLine(prevX, prevY, xScreen, yScreen);
            }
            prevX = xScreen;
            prevY = yScreen;

        }
    }
}
```


irgendwo ist noch ein Fehler, ich denke mal das ist der im Interface, wo der Identifier erwartet wird.


zu meinen Koordinatensystem: Ich werde es noch ein bisschen aufarbeiten, sobald ich Zeit dafür finde. Wahrscheinlich ein bisschen variabler, die getWidth und getHeight Funktionen sind da nicht schlecht


----------



## Marco13 (21. Okt 2009)

Ne, das Function interface steht nur "leer" irgendwo rum

```
interface Function
{
    float evaluate(float x);
}
```

Das
Plotter *implements Function*
kann auch weg.

Und in der Main, wo du das "Plotter"-Objekt erstellst, steht im Moment sowas wie

```
Plotter plotter = new Plotter();
plotter.FunktionsPlotter();
```
und jetzt dann halt sowas wie


```
Plotter plotter = new Plotter();

Function function = new Function()
{
    public float evaluate(float x)
    {
        return 2*x+3;
    }
};
plotter.setFunction(function);

plotter.FunktionsPlotter();
```


----------



## Underworld (21. Okt 2009)

dummerweise haben wir nicht besprochen, was die Main ist, jedoch kann ich mir das vorstellen.

Aber wie kann ich denn die Main im BlueJ verändern?
Ist das einfach das was wo public class Plotter steht?

also so?:


```
import java.awt.*;
import javax.swing.*;

Plotter plotter = new Plotter();

Function function = new Function()
{
    public float evaluate(float x)
    {
        return 2*x+3;
    }
};
plotter.setFunction(function);

plotter.FunktionsPlotter();

class Plotter {

interface Function
{
    float evaluate(float x);
}
```

hm, ist die Main vllt das Kästchen da unten? Wenn ich das da reinschreibe, kommt aber immer noch ein error

Naja, bin jetzt erstmal beim Training, danach schau ich kurz nochmal rein, morgen ist ja leider wieder Schule ^^


----------



## Marco13 (21. Okt 2009)

Oh je - die wurde wegrationalisiert? :autsch: Mann ... naja, um's zum Laufen zu hacken

```
public void FunktionsPlotter() {
if (function == null) 
{
    function = new Function()
    {
        public float evaluate(float x)
        {
            return 2*x+3;
        }
    };

    ...
}
```


----------



## Underworld (22. Okt 2009)

also, ich hab den Funktionplotter mittlerweile so wie ich das haben möchte!

Wollte mich nur noch mal für die tolle Hilfe von Marco13 bedanken!

Fand ich super, dass du mir relativ schnell und vor allem ausführlich geantwortet hast, wenn ich nicht weitergekommen bin! So ein Engagment sieht man recht selten :toll:

lg Flo


----------

