Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Okt 19, 2018 13:52

Foren-Übersicht » Sonstiges » Projekte
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 2 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Funktionszeichner
BeitragVerfasst: Mo Feb 21, 2011 14:12 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Dez 11, 2009 08:02
Beiträge: 532
Programmiersprache: pascal (Delphi 7)
(ein besserer Titel ist mir nicht aingefallen)

also, dann stell ich halt auch mal ein Projekt vor. Ist nichts großartiges, und hat noch nicht mal was mit OpenGL zu tun, aber was solls.

Also, mein Projekt ist so ein Zeug, wo man eine Funktion einzippt, und die wird dann gezeichnet.
Folgende Operatoren werden Unterstützt:
+, -, *, /, ^, log, wobei der Logarithmus von a zur Basis b als 'b log a' geschrieben wird
zusätzlich werden folgende Funktionen bislang unterstützt:
sin, cos, ln, sgn, abs, trunc
die kann man entweder so schreiben: 'sin(x)' oder aufgrund von etwas, was eigentlich ein Bug ist auch so 'x sin'.
insgesamt kann die Eingabe zB so aussehen: 'x * y = 1', 'sin(x) = cos(y)', etc
gezeichnet wird bei Doppelklick auf die PaintBox. Momentan muss die eingabe allerdings einzeilig sein (wird ggf noch geändert). Gezeichnet wird die Funktion jeweils von -10 bis 10 (sowohl x als auch y) Später wird man das aber auch noch festlegen können.
Gezeichnet wird, indem erst für jedes Pixel ein Weit berechnet wird (das '=' subtrahiert den rechten Wert vom linken, funktioniert also genauso wie das '-', mit dem Unterschied, dass es erst als letztes angewandt wird) dann werden alle Pixel eingefärbt, deren Vorzeichen sich vom Vorzeichen eines beliebigen Nachbarpixels unterscheidet (weil dann dazwischen irgendwo eine 0 sein muss (Annahme: Die Funktion sei stetig. Wenn das nicht zutrifft, entstehen Linien, die nicht sein sollten) Ich schätz mal, ich muss nicht noch genauer erklären, wie Vergleiche funktionieren ;) ). Zusätzlich zu '=' werden auch noch '<', '>', '<=', '>=' unterstützt. Übrigens benutze ich derzeit Canvas.Pixels, was das Ganze etwas langsam erscheinen lässt.

So. Damit wäre mal erklärt, wie das Zeichnen funktioniert. Was aber (meiner Meinung nach) wesentlich interessanter ist, ist, wie die Eingaben geparst werden. Ok, auch nichts wirklich besonderes, aber egal.
Also, erstes Problem ist einmal, die sache mit * vor + und so. Die Lösung dazu ist recht einfach:
Ich fange beim letzten Operator (der, der als letztes ausgeführt werden soll) an, und mache dann folgendes:
1) Alle existierenden Klammern verdoppeln (damit keine Fehler entstehen, wenn ich nachher mehr oder weniger blind Klammern setze)
2) ganz vorne und ganz hinten eine Klammer hinzufügen (damit nicht die erste Klammer zu vor der ersten Klammer auf sein kann)
3) den aktuellen Operator ausklammern (also zB '+' wird zu ')+(')
damit wäre dann sichergestellt, dass dieser Operator erst nach dem angewandt wird, der erst später (oder gar nicht) ausgeklammert wird.
Das Mache ich in Folgender Reihenfolge: als erstes =, dann + und -, dann * und /, und zuletzt noch ^ und log
Damit wäre dieses Problem einmal gelöst, und es funktioniert

Nächstes Problem: Einige Operatoren stehen zwischen den Operanden. Das ist aber der einzige Ort, an dem ich sie ganz sicher nicht brauchen kann
Die Lösung dafür ist auch nicht allzu schwierig, ich benutze einfach eine Funktion, die solange keine Klammern auftauchen (um die Operatoren zwischen den Operanden tauchen immer Klammern auf, weil die zuvor gesetzt wurden) einfach alles noch einmal so aneinanderreiht, wie es eh schon dasteht. Wenn Klammern auftauchen ruft sich die Funktion rekursiv selbst auf, und reiht die Teile so aneinander: Teil in den Klammern + Teil links von den Klammern + Teil rechts von den Klammern. Dabei kennzeichne ich gleich auch jeden Operator als solchen (zB wird + zu OP+) Variablen und Konstanten werden auch jeweils als solche gekennzeichnet. Das Ganze erleichtert dann gleich auch den nächsten Schritt.

Mit einem String kann man aber nachwievor nicht viel anfangen. Was ich brauche sind Funktionszeiger. Auch kein allzu großes Problem. Immerhin steht das Ganze bereits quasi-assembler artig da, es in Funktionszeiger zu übersetzen ist also auch kein wirkliches Problem mehr. Dabei habe ich neben den bereits erwähnten Operatoren eigentlich nur noch zwei Funktionen, auf die gezeigt werden kann. die heißen PushVar und PushConst (gerechnet wird gewissermaßen auf einem Stack) Jetzt ists ganz praktisch, dass ich bereits zwischen Operatoren (bzw Funktionen), und Variablen/Konstanten unterschieden habe (wobei man das natürlich eigentlich genausogut auch erst hier machen könnte).
Jedenfalls PushVar setzt einen bereits am Stack befindlichen Wert oben nochmal drauf, PushConst setzt eine Konstante oben drauf.
Das Problem bei der Sache ist jetzt, dass PushVar als Parameter einen Index braucht, ich aber keinen übergeben kann, weil sonst die Funktionszeiger nicht mehr darauf zeigen könnten. Egal, der Parameter kommt einfach in den nächsten Funktionszeiger, der dann dafür übersprungen wird. Dasselbe gilt auch für PushConst, nur dass der gleich zwei Parameter braucht (weil ich mit double rechne, also 64 bit)

Bevor zu rechnen angefangen wird, werden noch Werte für x und y auf den Stack gelegt, und fertig.

so, das wars eigentlich schon, einziges, was vielleicht noch erwähnenswert ist, ist, dass ich (aus Geschwindigkeitsgründen) immer für alle Pixel "gleichzeitig" rechne, also ein Funktionsaufruf ein recht großes Array bearbeitet.

übrigens: groß/KLEIN-schreibung ist nicht egal. grundsätzlich wird alles klein geschrieben.

edit: diesmal nur die exe:
Dateianhang:
funktionszeichner.zip [216.67 KiB]
202-mal heruntergeladen

und in einem seperaten Archiv der code:
Dateianhang:
code.zip [9.53 KiB]
181-mal heruntergeladen


Zuletzt geändert von sharkman am Mo Apr 04, 2011 18:06, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Funktionszeichner
BeitragVerfasst: Do Feb 24, 2011 11:31 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Dez 11, 2009 08:02
Beiträge: 532
Programmiersprache: pascal (Delphi 7)
1) Was mir erst gar nicht aufgefallen ist: das Zeug hat keine Vorzeichen akzeptiert (- war immer das Zeichen für Subtraktion) Dieser Bug ist behoben, einfach indem ich als erstes alle -, die Vorzeichen sind durch ein anderes Zeichen ersetze, das sicher nicht vorkommt. Das Vorzeichen erkenne ich daran, dass davor eine Klammer auf, ein anderer Operator, oder nichts steht.

2) Wenn bei irgendeiner Berechnung infinity oder NaN rauskommt, schreit Delphi, mit dem Ergebnis, dass nix gezeichnet wird. Also frag ich jetzt einfach alle solchen fälle ab, und weise dann manuell infinity bzw NaN zu. sieht zwar doof aus, wo die Hardware das doch eh kann, und machts auch nicht gerade schneller, aber es funktioniert, und der Flaschenhals ist nachwievor das Canvas.Pixels

3) der Bereich, in den Gezeichnet wird, kann jetzt festgelegt werden.

4) arcsin und arccos gibts jetzt auch.

edit: musste es zwar auf zwei Dateien aufteilen, aber der Download im ersten Beitrag funktioniert wieder.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 2 Beiträge ] 
Foren-Übersicht » Sonstiges » Projekte


Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 2 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.032s | 17 Queries | GZIP : On ]