Entwickler-Ecke

Open Source Projekte - Grapher - Ein Funktionsgraphenzeichner


AdrianK - Sa 18.07.09 13:41
Titel: Grapher - Ein Funktionsgraphenzeichner
Grapher Website [http://adriank.bplaced.net/index.php?kat=grapher]

Grapher ist ein in C Sharp programmierter Funktionsgraphenzeichner. Er verwendet eine von mir programmierte Parser-Klasse [http://adriank.bplaced.net/index.php?kat=mathparser].

Features:
Das Programm steht unter der GPLv3 und ist lauffähig unter Linux (Mono), Windows (.NET) und warscheinlich auch MacOSX (Mono, nicht getestet)

Download
Das kompilierte Programm für .NET / Mono kann man auf meiner Website hier herunterladen [http://adriank.bplaced.net/files/Grapher.exe]. Den Sourcecode gibts hier: Download Grapher-Source [http://adriank.bplaced.net/files/GrapherSrc.rar]


Screenshots

[url=http://adriank.bplaced.net/images/grapher_001.png]user defined image[/url]

[url=http://adriank.bplaced.net/images/grapher_002.png]user defined image[/url] [url=http://adriank.bplaced.net/images/grapher_003.png]user defined image[/url]


fireworker - Sa 18.07.09 14:13

Eine Frage:

Ich habe da mal 2x eingegeben (also y=2x), und jeztz gibt er mir anstelle einer geraden eine etwas komische kurve an. Das müsste doch laut meinen noch in Grenzen gehaltenen Mathekünsten nicht richtig sein, oder?

mfG


AdrianK - Sa 18.07.09 14:46

Nein, dass ist nicht richtig... ^^
Ich habe vergessen zu erwähnen das negative Zahlen immer in Klammern geschrieben werden müssen (also auch x -> wird ja auch negativ)
Es müsste dann also so heisen:

Quelltext
1:
y=2*(x)                    


InCoBra - Sa 18.07.09 17:08



[1]

Quelltext
1:
2:
3:
(2 + 3)(2 + 3) = (2 + 3) * (2 + 3)

2x = 2 * x


Ich weiß, viel negatives, aber ich sag es ja nicht um dich zu ärgern, sondern um dir die Möglichkeit zu geben, dein Programm zu verbessern!


Th69 - So 19.07.09 10:21

Hallo Adrian,

in einem anderen C#-Forum habe ich auch einen Mathe-Parser gepostet, der sehr flexibel ist. Ein einfaches Graphen-Programm (Graph.zip) ist auch zum Download dabei:
http://www.mycsharp.de/wbb2/thread.php?threadid=71995

Kannst dir ja mal meinen Parser anschauen... denn deiner hat ja doch noch ein paar Schwächen.
Die weiteren Features deines Programms sind aber gut.


AdrianK - Mo 20.07.09 14:04

Danke für das viele Feedback! ^^
Das mit dem Parser war mir klar, x sollte immer in einer Klammer stehen (weil negativ).
Deswegen funktioniert x*2 und 2*x nicht. Es müsste 2*(x) heisen. Das mit den Leerzeichen ist mir noch nicht aufgefallen, werde es beheben (das mit den Fehlermeldungen auch). Multiselect wirds auch geben. Deinen Parser werde ich mir mal anschauen.
:)


Jakob_Ullmann - Mo 20.07.09 16:16

Das klingt so, als ob du nur "x" im String durch den entsprechenden Wert ersetzt (hab mir den Parser nicht angesehen). Das ist nicht gerade sauber. Falls das so ist, wäre ein Workaround, x durch (Wert) zu ersetzen. Aber besser wäre eine saubere Lösung.

Sieht ansonsten schon sehr gut aus. Zwei Wünsche habe ich aber: Farbwahl und Achsenbeschriftung.


AdrianK - Mo 20.07.09 16:37

Ja, ich ersetze x einfach durch den wert. Meinst du das so:
x ist z.B. -2
x im String wird nicht durch -2 sondern durch (-2) ersetzt oder?
@Edit: Farbwahl und Achsenbeschriftung wird noch kommen.


Jakob_Ullmann - Mo 20.07.09 17:28

Genau so meine ich das. Aber wie gesagt: Sauber ist das nicht gerade. Ich weiß nicht, wie du den String verarbeitest. Aber falls du rekursiv arbeitest, ist das eigentlich leicht getan, einfach zu prüfen, ob ein auszuwertender Teilstring ein x ist und der entsprechende Wert wird zurückgegeben.


Th69 - Di 21.07.09 10:19

Hallo Jakob,
sein Parser arbeitet rein auf Stringersetzung (und ohne Operatorprioritäten etc.).

Wenn er wirklich sein Graph-Programm professionell entwickeln will, dann soll er einfach meinen Parser einsetzen (s. mein Beitrag oben).

Jedoch sind auch noch andere Anfängerfehler in dem Code:
- Verwendung von Graphics.Create() vermeiden (stattdessen e.Graphics verwenden!!!)
- zum Neuzeichen DrawGround.Invalidate() verwenden (anstatt DrawAllGraphs(), welche Graphics.Create() verwendet)
- der Parser sowie die Wertetabelle arbeitet nur mit ganzen Zahlen (int statt double) und dann wird DrawCurve (Splines) aufgerufen, d.h. falsche Darstellung von der Sinuskurve etc.
- ...


Jakob_Ullmann - Di 21.07.09 10:58

Ja, den Code habe ich mir -- wie gesagt -- noch nicht angesehen. Aber das ist dann natürlich sehr unschön. Irgendwann hatte ich mal einen rekursiv arbeitenden Parser in C# angefangen, aber irgendwie ist der in Vergessenheit geraten (bzw. eigentlich nur eine Delphi-C#-Portierung meines Delphi-Parsers).


AdrianK - Di 21.07.09 13:15

Der Parser und die Wertetabelle arbeiten mit double, das zeichnen nicht. (So hattest du es sicher gemeint) Ich muss ja die Werte runden, ich brauche ja Pixelangaben.
Die Operatorprioritäten werden aber beachtet, ich berechne ja zuerst ^, dann * usw.
Das Mit Graphics.Create() werde ich beheben, dass mit Invalidate auch.


Th69 - Di 21.07.09 18:49

Sorry Adrian, da habe ich mich nicht ganz korrekt ausgedrückt.
Ich meinte damit, daß du sowohl beim Parser als auch bei der Wertetabelle die x-Werte nur als int hast (deine for-Schleifen!). Bei der Wertetabelle wäre es daher noch gut, wenn man noch eine Schrittweite eingeben könnte (z.B. 0.1), denn z.B. die Sinuswerte 'sin(x)' von 0, 1, 2, 3,... machen wenig Sinn.
Schau dir einfach mal mein Graph-Programm an (s. Link oben)...
du machst es dir teilweise selbst kompliziert.

P.S. Du darfst gerne meinen Parser in dein Programm integrieren (dafür habe ich ihn ja ins Forum gestellt).


jfheins - Di 21.07.09 23:17

Ich habs mal ausprobiert:

- 1. Versuch: Y = 1/x ==> Fehler (also bitte, nur wegen dem einen Punkt...)

- 2. Versuch: sin(x) Ja hey - klappt

- 3. Versuch: x-x^3 ==> Fehler beim Hinzufügen des Funktionsgraphen

Nagut, dann halt (x)-(x)^3 ==> Fehler beim Hinzufügen des Funktionsgraphen Dabei wird noch nichtmal durch 0 geteilt?

Dann halt wieder löschen ==> System.OverflowException: Der Wert für einen Int32 war zu groß oder zu klein.
bei System.Convert.ToInt32(Double value)
bei Grapher.frmMain.DrawAllGraphs(Graphics graph)

=> Beenden :P

Nette Fingerübung, aber nicht viel mehr ;)


AdrianK - Mi 22.07.09 13:01

Ich denke ich muss wirklich einen neuen Parser schreiben... :oops:
@Th69: Ja, ich werde mir dein Programm mal anschauen, aber deinen Parser werde ich nicht verwenden, dabei lerne ich nichts :)


Jakob_Ullmann - Mi 22.07.09 15:15

Du kannst dir ja mal den hier ansehen: http://delphi.zsg-rottenburg.de/parser.html ist zwar Delphi, aber das Prinzip sollte ja bei C# dasselbe sein.


Kha - Mi 22.07.09 18:09

user profile iconJakob_Ullmann hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst dir ja mal den hier ansehen: http://delphi.zsg-rottenburg.de/parser.html ist zwar Delphi, aber das Prinzip sollte ja bei C# dasselbe sein.
Naja, mehr als String-Gewurstel ohne theoretische Grundlage ist das aber auch nicht ;) .

Einen denkbar einfachen Recursive Descent Parser habe ich hier [http://c-sharp-forum.de/viewtopic.php?p=562123#562123] gepostet. Der von Th69 fügt noch ein paar ;) Features hinzu.


Jakob_Ullmann - Mi 22.07.09 18:47

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconJakob_Ullmann hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst dir ja mal den hier ansehen: http://delphi.zsg-rottenburg.de/parser.html ist zwar Delphi, aber das Prinzip sollte ja bei C# dasselbe sein.
Naja, mehr als String-Gewurstel ohne theoretische Grundlage ist das aber auch nicht ;) .


Wieso String-Gewurstel? Und die theoretische Grundlage ist doch auch gegeben (auch wenn das jetzt nicht gerade auf EBNF oder regulären Grammatiken aufbaut).


Kha - Mi 22.07.09 21:14

user profile iconJakob_Ullmann hat folgendes geschrieben Zum zitierten Posting springen:
Wieso String-Gewurstel?
a) Statt den String einmal von links nach rechts durchzugehen, wird mit Pos0 wild herumgesucht - und zwar unnötig oft. O(n²) muss nun wirklich nicht sein, selbst wenn es niemandem wehtut ;) .
b) Vorverarbeitung durch MalZeichenSetzten (sic!)

user profile iconJakob_Ullmann hat folgendes geschrieben Zum zitierten Posting springen:
Und die theoretische Grundlage ist doch auch gegeben (auch wenn das jetzt nicht gerade auf EBNF oder regulären Grammatiken aufbaut).
Die Vorgehensweise wird erläutert, ja. Aber unter "Theorie" verstehe ich einen allgemeinen Algorithmus, der nicht nur auf dieses spezielle Problem angewendet werden kann.
Natürlich ist die Logik des Parsers leicht verständlich, aber an manchen Stellen dann doch wieder unnötig kompliziert im Vergleich zur einfach absolut direkten Logik eines LL-Parsers. Viel Spaß dabei, TermToReal das unäre Minus beizubringen ;P .


Jakob_Ullmann - Mi 22.07.09 23:23

Klar ist der nicht so schön, aber mit etwas Zuarbeit habe ich es geschafft, da schon einen leistungsfähigen Parser zu basteln. Aber deine Warnung nehme ich natürlich gerne auf, da der momentane dcCalc-Parser nur eine Erweiterung des verlinkten Parsers ist (wobei der aber bei größeren Wertetabellen noch nie Geschwindigkeitsverluste gezeigt hat).


AdrianK - Do 23.07.09 13:09

Ich habe nocheinmal meinen Parser etwas verbessert (Leerzeichen werden automatisch entfernt, 2x oder 4(3+2) geht jetzt und man muss x nicht mehr in eine Klammer setzen), und die Probleme liegen nicht an dem Parser, sondern an der Zeichenfunktion.