| Autor |
Beitrag |
XZeranski
      
Beiträge: 38
|
Verfasst: 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:
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
      
Beiträge: 1206
Erhaltene Danke: 1
|
Verfasst: 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 
      
Beiträge: 38
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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... 
|
|
XZeranski 
      
Beiträge: 38
|
Verfasst: 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:
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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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...: 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 so drawFunc(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 
      
Beiträge: 38
|
Verfasst: 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
      
Beiträge: 647
WinXP + fbsd
Delphi 5 Prof
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Di 03.06.03 16:59
Hi! Hier mal so, wie ich es eigentlich gemeint hatte:
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 X := MinX + Spalte/PixelProBreiteneinheit; Y := X*X; Reihe :=Image1.Height -Trunc(Y*PixelProHoehenEinheit-MinY*PixelProHoehenEinheit);
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 tommie-lie: Code- durch Delphi-Tags ersetzt
|
|
XZeranski 
      
Beiträge: 38
|
Verfasst: Di 03.06.03 18:20
Boah, Respekt.
Ich kann dir nicht genug danken
Das funktioniert perfekt!!!
Danke Danke Danke !!!!
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: Mi 04.06.03 12:01
@Udontknow: Das is auch nach meinem geschmack
@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:
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; ... function aFunc(x:real):real; begin result := x*x; end; ... function anotherFunc(x:real):real; begin result := x*x*x-4; 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 X := MinX + Spalte/PixelProBreiteneinheit;
if func <> nil then Y := func(X); Reihe :=Image1.Height -Trunc(Y*PixelProHoehenEinheit-MinY*PixelProHoehenEinheit);
Image1.Canvas.LineTo(Spalte,Reihe); end; end; | ...und beim aufrufen gibst du einfach die, zu zeichnende funktion mit an: Delphi-Quelltext 1: 2: 3:
| ZeichneFunktion(0, 0, 400, 300, aFunc); ZeichneFunktion(0, 0, 400, 300, 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
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: 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
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: Mi 04.06.03 12:46
Titel: Okay ... gerade selber eine Idee gehabt ...
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 tommie-lie: Code- durch Delphi-Tags ersetzt
_________________ Euer Mäxchen
Wer früher stirbt, ist länger tot.
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: Mi 04.06.03 13:17
 Âuch geil
Würd aber vorschlagen, dass XZeranski erstma alles stück für stück assimiliert. 
_________________ mfg.
mâximôv
|
|
MaxiTB
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: 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. 
_________________ Euer Mäxchen
Wer früher stirbt, ist länger tot.
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: Mi 04.06.03 14:35
Ja genau...deine charaktereigenschaften werden meinen hinzugefügt werden  ..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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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...
Cu,
Udontknow
|
|
Tomac
      
Beiträge: 113
Win XP
D6 Ent
|
Verfasst: 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
      
Beiträge: 647
WinXP + fbsd
Delphi 5 Prof
|
Verfasst: 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...
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 
      
Beiträge: 38
|
Verfasst: 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..
|
|
|