Autor Beitrag
XZeranski
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Mo 02.06.03 18:01 
Hallo, habe folgendes Problem
Ich habe z.b. die Funktion y = x * x und will diese graphisch darstellen lassen.
Dazu habe ich einmal diesen Code:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.Button1Click(Sender: TObject);
var p,r : integer;
      y,z,x : real;
begin
x := -5;
Repeat
y := x * x;
image1.Canvas.Pixels [round(x*35)+175,round(-y*35)+175]:= clblack;
x := x + 0.01;
Until x > 5;

Hier ist jedoch das Problem, das ich bei einem größeren Bereich und größeren Berich eine viel zu lange Rechenzeit habe.

Dann hatte ich noch einen zweiten Weg mit "MoveTo" und "LineTo" Aber das war auch nicht sehr viel schneller.

Wie kann ich es schaffen dass ich eine sehr kurze Rechenzeit habe, auch bei sehr großen Bereichen und komplizierteren Funktionen?[/delphi]
neojones
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1206
Erhaltene Danke: 1



BeitragVerfasst: Mo 02.06.03 18:22 
Nachdem ja auf jedes Pixel nur ein Punkt des Graphen passt musst Du auch nur für jeden Pixel die Berechnung anstellen. Ich denke mal, dass man das am Besten iterativ macht und sagt, man stellt zunächst die beiden äußeren Pixel dar und dann den Pixel exakt dazwischen und dann wieder den mittleren zwischen dem äußersten und dem mittleren und dann wieder den mittleren zwischen den bestehenden und wenn kein Pixel mehr dazwischen passt, hört man einfach auf.

Das müsste bei so einem relativ geregelten Graphen ganz gut funktionieren.

Viele Grüße,

Matthias

_________________
Ha! Es compiliert! Wir können ausliefern!
XZeranski Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Mo 02.06.03 18:32 
Danke für deinen Tip, aber irgendwie wüsste ich gar nicht wie ich da rangehen sollte bzw. wie du das genau meinst.
Wär echt toll wenn du das noch etwas näher erläutern könntest.
Danke!!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 02.06.03 19:33 
Hiho!

Wir hatten das Thema ja schon, bin leider nicht dazu gekommen...

Also:

Nehmen wir mal an, dein Graph-Image ist 200px breit und 200px hoch.

Dann musst du verschiedenes erst einmal festlegen:
-Wenn für die erste Spalte (X-Koordinate 0) ein Wert eingezeichnet wird, was ist das dann für ein X-Wert in deiner Funktion?
-Wenn du nun eine Spalte weitergehst, um wieviel verändert sich dein eigentlicher X-Wert der Funktion?

Würdest du beispielsweise den Bereich von -100 bis +100 darstellen wollen, so gilt folgende Funktion:

X = -100 + Spalte

Willst du dagegen nun von -2 bis +2 darstellen, so gilt:

X = -2 + Spalte /200*4

Oder allgemein

X = MinX + Spalte/GraphBreite*(MaxX-MinX)

Das gleiche gilt dann natürlich im umgekehrten Sinne für die Y-Achse:
Auch da musst du festlegen, welchen Wertebereich du darstellen lassen willst, allerdings musst du dieses Mal nicht den Y-Wert der Funktion durch die Reihe errechnen, sondern die Reihe (Y-Koordinate des Images) durch die Funktion und den zugehörigen Funktionswert.

Cu,
Udontknow

PS: Wer kann, der nehme eine TChart-Komponente... :wink:
XZeranski Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Mo 02.06.03 19:57 
Ich muss also meinen "Erhöhungsschritt" von X an den anzuzeigenden Bereich anpassen?
Habe ich das so richtig verstanden?

Also z.b. mein Image ist 350 * 350 groß. Und ich will z.b. die Funktion y = x*x über den ganzen Bereich darstellen lassen.

Dann muss ich bei -350 starten und x jeweils um 1 erhöhen.
Dazu habe ich folgendes geschrieben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.Button1Click(Sender: TObject);
var p,r,x : integer;
      y,z : real;
begin
x := -350;
Repeat
y := x*x;
image1.Canvas.Pixels [(x*35)+175,round(-y*35)+175]:= clblack;
x := x + 1;
Until x > 350;
end;

end.


Mit 35 erreiche ich ja das die Parabel wieder im richtigen Maßstab angezeigt wird, und mit 175 hole ich sie in die Mitte des Images, weil ja das Koordinatensystem (das ich auch gezeichnet habe) den Nullpunkt in der Mitte hat.

Allerdings hat mein Programm oben einen Haken. Wenn ich es starte sehe ich nur 5 Punkte die gezeichnet wurden und auch eine Parabel beschreiben, aber die Punkte sind auch nicht verbunden. Was mache ich da noch falsch?[/code]
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Di 03.06.03 14:43 
Hi...

wenn ich das richtig sehe, wäre die '35' deine skalierung...das würde ich alles als parameter/variable von einer funktion machen lassen...dann kann man besser mit den werten spielen. 35 scheint mir auch ein bisschen hoch.

Abgesehen davon, skalierst du die ausgabe-pixel und nicht die eingabe in deine funktion! zB. so...:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.drawFunc(scale:single); 
var p,r,x : integer; 
      y,z : real; 
begin 
  x := -350
  Repeat 
    y := (x*scale)*(x*scale); 
    image1.Canvas.Pixels [(x)+175,-trunc(y/scale)+175]:= clblack; 
   x := x + 1
  Until x > 350
end;
...würd ich es schon eher machen. nicht getestet.

Und aufrufen tust du's dann sodrawFunc(0.023)

Aber deine frage, war ja, was am schnellsten ist. Du kannst es noch beschleunigen, indem du 'scanline' benutzt. ich würd allerdings linien zwischen den punkten zeichnen (LineTo oder so).

viel erfolg

_________________
mfg.
mâximôv
XZeranski Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Di 03.06.03 16:23 
Vielen Danke für deine Hilfe, das hat super geklappt.
Jetzt habe ich nur noch zwei Fragen :)
1. Wie bist du auf die 0.023 gekommen?

2. Wie schaffe ich es das die Punkte verbunden sind, und keine Zwischenräume mehr frei sind?
Tweafis
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 647

WinXP + fbsd
Delphi 5 Prof
BeitragVerfasst: Di 03.06.03 16:38 
XZeranski hat folgendes geschrieben:
2. Wie schaffe ich es das die Punkte verbunden sind, und keine Zwischenräume mehr frei sind?


Du machst ganz am Anfang moveTo(0, Height div 2) oder je nachdem wo dein Graph anfängt, und dann immer LineTo(nächsterPunktX, nächsterPunktY)

_________________
.: Es wird der Tag kommen, an dem wir es nicht mehr ändern können :.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Di 03.06.03 16:59 
Hi! Hier mal so, wie ich es eigentlich gemeint hatte:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TForm1.ZeichneFunktion(MinX, MaxX, MinY, MaxY: Real);
var Reihe,Spalte:Integer;
var X,Y:Real;
var PixelProHoeheneinheit:Real;
var PixelProBreiteneinheit:Real;
begin
  PixelProHoeheneinheit:=Image1.Height/(MaxY-MinY);
  PixelProBreiteneinheit:=Image1.Width/(MaxX-MinX);

  Image1.Canvas.MoveTo(-2,0);
  for Spalte:=-1 to Image1.Width-1 do
  begin
    //Was für ein X-Wert der Funktion entspricht dieser Spalte?
    X := MinX + Spalte/PixelProBreiteneinheit;
    //Y-Wert zu X-Wert durch Funktion berechnen
    Y := X*X;
    //Was für eine Reihe entspricht dem errechneten Y-Wert?
    Reihe :=Image1.Height -Trunc(Y*PixelProHoehenEinheit-MinY*PixelProHoehenEinheit);

    //Zeichnen
    Image1.Canvas.LineTo(Spalte,Reihe);
  end;
end;


Du übergibst einfach die entsprechenden Grenzen für den Graphen (-2,2,-10,10), um im Definitionsbereich -2 bis 2 den Wertebereich -10 bis +10 zu betrachten.

Cu,
Udontknow


Moderiert von user profile icontommie-lie: Code- durch Delphi-Tags ersetzt
XZeranski Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Di 03.06.03 18:20 
Boah, Respekt.
Ich kann dir nicht genug danken :D
Das funktioniert perfekt!!!
Danke Danke Danke !!!!
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 04.06.03 12:01 
@Udontknow: Das is auch nach meinem geschmack :wink:

@XZeranski: wenn du ganz crazy drauf bist, dann packst du die eigentliche f(x)-funktion in eine externe funktion und übergibst der zeichen-routine noch zusätlich einen pointer auf diese...hat den vorteil, du kannst viele verschiedene graphen mit der selben routine-zeichnen lassen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
type pFx = function(x:real):real; // functions-pointer-type erstellen
...
function aFunc(x:real):real; // parameter-definition muss hier mit den typ pFx übereinstimmen
begin
  result := x*x;
end;
...
function anotherFunc(x:real):real; // parameter-definition muss hier mit den typ pFx übereinstimmen
begin
  result := x*x*x-4// könntest hier den Y-abschnitt auch parametrisieren (b)
end;
...
procedure TForm1.ZeichneFunktion(MinX, MaxX, MinY, MaxY: Real; func: pFx ); 
var Reihe,Spalte:Integer; 
var X,Y:Real; 
var PixelProHoeheneinheit:Real; 
var PixelProBreiteneinheit:Real; 
begin 
  PixelProHoeheneinheit:=Image1.Height/(MaxY-MinY); 
  PixelProBreiteneinheit:=Image1.Width/(MaxX-MinX); 

  Image1.Canvas.MoveTo(-2,0); 
  for Spalte:=-1 to Image1.Width-1 do 
  begin 
    //Was für ein X-Wert der Funktion entspricht dieser Spalte? 
    X := MinX + Spalte/PixelProBreiteneinheit; 

    //Y-Wert zu X-Wert durch Funktion berechnen 
    if func <> nil then Y := func(X); // externe funktion aufrufen

    //Was für eine Reihe entspricht dem errechneten Y-Wert? 
    Reihe :=Image1.Height -Trunc(Y*PixelProHoehenEinheit-MinY*PixelProHoehenEinheit); 

    //Zeichnen 
    Image1.Canvas.LineTo(Spalte,Reihe); 
  end
end;
...und beim aufrufen gibst du einfach die, zu zeichnende funktion mit an:
ausblenden Delphi-Quelltext
1:
2:
3:
ZeichneFunktion(00400300, aFunc); 
//...oder
ZeichneFunktion(00400300, anotherFunc);
...wenn du dann noch nicht dann noch nicht genug hast, dann könntest du alle erstellten F(x)-funktionen in eine ListBox eintragen, mit namen und pointer, und lustig mit der maus auswählen.

mfg maximus

_________________
mfg.
mâximôv
MaxiTB
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Mi 04.06.03 12:38 
Titel: Frage ...
... das mit den Funtionsreferenz gefällt mir ja ganz gut, aber:

Unter C ist es möglich - kann ich auch unter Delphi Funktionen mit variabler Parameterliste implementieren und diese als Referenz dann übergeben ?

Oder packt der Compiler den Praxistest dann doch nicht ?

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.
MaxiTB
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Mi 04.06.03 12:46 
Titel: Okay ... gerade selber eine Idee gehabt ...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
type TFunc=class(TObject)
  private
    fMin: integer;
    fMax: integer;
    fMode: integer;
  public
    function Execute(aIndex: integer);

    property Mode: integer read fMode write fMode;
    property Min: integer read fMin write fMin;
    property Max: integer read fMax write fMax;
end;


So einfach ging es für variable Paramter und wäre sogar noch richtig schön ...

Was das soll ? Hehe, ganz einfach, ist nur die Basisklasse einer beliebigen Funktion.

Die Range gibt eine beliebige Weite in x oder y an, mit Mode kann man angeben über welchen Parameter man es macht und Execute gibt dann die einzelenen Werte zurück. Ranging und alles kann man schön in die Basisklasse implementieren ... sowas wäre ja wirklich ein cooles Teil - werde vielleicht mal, wenn ich lust habe, eine ultimative Graphenklasse basteln ;-)


Moderiert von user profile icontommie-lie: Code- durch Delphi-Tags ersetzt

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 04.06.03 13:17 
:roll: Âuch geil :D

Würd aber vorschlagen, dass XZeranski erstma alles stück für stück assimiliert. :wink:

_________________
mfg.
mâximôv
MaxiTB
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Mi 04.06.03 13:22 
Titel: Noch n Borg ...
War ja nur eine Idee ... bin ja schon still, weil ich weiß, Widerstand ist zwecklos. :lol:

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 04.06.03 14:35 
Ja genau...deine charaktereigenschaften werden meinen hinzugefügt werden 8) ..eigentlich ziemlich dumm von den borg!..wenn da mal'n Charakter-Schwein dabei ist, dann is gleich das ganze Kollektiv versaut :)

_________________
mfg.
mâximôv
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mi 04.06.03 16:52 
Um das ganze auf die Spitze zu treiben: Wie wäre es mit einem Funktionsinterpreter? Man gibt die Funktion als String ein, und tadaaa, schon erscheint sie im Graphen... :wink:

Cu,
Udontknow
Tomac
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 113

Win XP
D6 Ent
BeitragVerfasst: Mi 04.06.03 16:58 
Hi!

Ich habe das ganze mal mit einem Freund Programmiert, also einen Taschenrechner der so ziemlich alle Graphen zeichnen kann. (Für die Zerlegung der eingegebenen ´Funktionen verwendete ich einen fertigen Parser).

Das ganze funktioniert allerdings wesentlich komplizierter, mit mehreren Funktionen zum Ausrechnen eines Optimalen Darstellungsbereichs bzw. Definitionsbereich und so weiter...

Wenn du willst, kann ich es dir schicken.

mfg
Tomac
Tweafis
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 647

WinXP + fbsd
Delphi 5 Prof
BeitragVerfasst: Mi 04.06.03 17:26 
Udontknow hat folgendes geschrieben:
Um das ganze auf die Spitze zu treiben: Wie wäre es mit einem Funktionsinterpreter? Man gibt die Funktion als String ein, und tadaaa, schon erscheint sie im Graphen... :wink:

Cu,
Udontknow


Ich kann mich noch an ein beispiel in Turbo Pascal errinnern wo das dann in ne externe pas geschrieben wurde und diese wurde dann compiliert.

Oder wie soll das sont gehen?
sowas wie eval gibts doch net.

Fis

_________________
.: Es wird der Tag kommen, an dem wir es nicht mehr ändern können :.
XZeranski Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 38



BeitragVerfasst: Mi 04.06.03 17:41 
@ Tomac : Das wäre echt nicht schlecht

@ UDontKnow : Sozusagen hab ich das auch, allerdings hatte ich mir den Parser dazu aus dem Internet geholt, selber hätte ich den nie hinbekommen.
Mein Graphenzeichnungsprogramm funktioniert jetzt so gut wie perfekt. Nur mit den Winkelfunktionen haut es nicht so richtig hin.
Damit diese korrekt angezeigt werden können, muss ein Umrechnungsfaktor von 55,7 eingebaut werden (mein Image ist 350 Pixel breit), wegen der Periode von 2*PI. Wie ich es allerdings schaffe das zu bewerkstelligen weiß ich noch nicht.
Habe dazu auch einen Thread aufgemacht,
www.delphi-forum.de/viewtopic.php?t=12242
hoffe das Problem kommt so einigermaßen rüber..