Re: How to plot simple 2D Graphs in C/C++ ?

Discussion in 'C++' started by Boris Glawe, Aug 25, 2003.

1. Boris GlaweGuest

Hi,

I wrote a plotter for the terminal a
long long time ago.
The function is hardcoded.
Many comments and some variable names
are in german...
And programming style is horrible, since
I wrote it a long long time ago ;-)

The code is attached to the message...

maybe it helps.

greets Boris

/* plotter.cpp Boris Glawe, 8.1.2002

Ausführbar auf Terminals mit einer Auflösung von 80x25
oder höher...
*/

#include <iostream.h>
#include <math.h>

#define TASTFREQ 80
#define ROWLENGTH 80 // Breite des Bildschirms
#define SCREENHEIGHT 50 // Höhe der Tabelle

/******************************************************************/

class Graph {

private:

long double tab[TASTFREQ]; //vertikale Breite
char row[ROWLENGTH+1]; // horizontale Breite (plus newline)

long double max; //maximalwert in Fkt.
long double min; //minimalwert in Fkt.

long double xa; //kleinster x-Wert
long double xe; //größter x-Wert -> dargestelltes Intervall...

long double f(long double x){
return sin(x) + sin(2*x) + sin(3*x) + sin(4*x);
}

/*Folgende Funktion ordnet einem Zahlenwert einen Feldindex zu.
Sie erwartet fünf Argumente.
1.Index des ersten Feldes im Array
2.Index des letzten Feldes im Array
3.Den kleinsten einzuordnenden Wert
4.Faktor, der den "Wert" eines Feldes angibt
5.der einzuordnende Wert
Es wird das Intervall zwischen einem Maximalwert und einem
Minimalwert in zwei Hälften geteilt.
Es wird geprüft, in welcher Hälfte der Wert liegt und der
selbe Vorgang wird mit dieser Hälfte solange rekursiv wiederholt,
bis ein eindeutiges Feld bestimmt ist...
Der rekursive Aufruf und die vielen Parameter machen das Programm
unübersichtlich, ersparen aber viele Rechenschritte...
*/

int classify(int a, int e,
long double minvalue, long double dx, long double v){

int anfang = a;
int ende = e;
int mitte;

if( (e - a) % 2 == 0) mitte = (e + a) / 2;
else mitte = (e + a -1) / 2;

if (mitte == a) return mitte ;

if(v >= minvalue + dx*(mitte) ){
anfang = mitte;
return classify(anfang,ende,minvalue,dx,v);
}
else{
ende = mitte;
return classify(anfang,ende,minvalue,dx,v);
}
}

void make_tab(){
long double dx = xa;
int i;

for (i=0; i<TASTFREQ; i++){
tab = f(dx);
dx += (xe - xa) / TASTFREQ;
}
}

void init_graph(){

int i;

//Finde Extremwerte des Graphen...
//falls alle fkt.-werte > 0 sind dann muss 0 trotzdem
//Minimum sein, damit die Achsen richtig gezeichnet werden
//Das gleich gilt, falls alle Wert < 0 sind...
max = 0;
min = 0;

for (i=0; i<TASTFREQ; i++){
if (tab > max) max = tab;
if (tab < min) min = tab;
}

//den array row[] reseten...
for(i=0; i<ROWLENGTH; i++){
row=' ';
}
}

public:

//Standardkonstruktor:Standardbereich 0 bis 2 PI...
Graph (){

xa = 0.0; xe = 2.0*M_PI;

make_tab(); // Tabellenwerte erstellen
init_graph(); // Eigenschaften des Graphen berechnen..

}

//Konstruktor: Parameter geben den Bildbereich an.
Graph (long double a, long double e){

xa = a; xe = e;

make_tab();
init_graph();

}//Ende Konstruktoren

void print_values(){
int i;

cout << "Min:\t" << min << endl;
cout << "Max:\t" << max << endl;

for (i=0;i<TASTFREQ; i++){
cout << tab << endl;
}

cout << endl << endl; // Abstand zur nächsten Ausgabe...

}

void draw_endless_graph() {

int i,k,zero_point;

//Normierung der Werte auf Arraylänge
long double fieldwidth = (max - min) / ROWLENGTH;

//Nullpunkt auf Bildschirmarray finden...
zero_point = classify(0,ROWLENGTH,min,fieldwidth,0.0);

// Kopfzeile schreiben...
cout << "MAX: " << max << "\t\tMIN: " << min << endl;

for(i=0; i<ROWLENGTH; i++) {
if (i == zero_point) cout << "0";
else cout << "-";
}
cout << endl;

/* Durchlaufe alle Werte in tab[] und ordne sie einzeln
in row[] ein...schreibe dann row[] auf Bildschirm */
for(i=0; i<TASTFREQ; i++){
row[zero_point] = '|';
k=classify(0,ROWLENGTH-1,min,fieldwidth,tab);
row[k] = '*'; row[ROWLENGTH] = 0;
cout << row << endl;// Einzeichnen des Fkt.-wertes

row[k] = ' '; // Feld wieder leeren...
}
//...und wieder aufräumen !!
for (i=0; i<ROWLENGTH; i++) { row = ' ' ; row[ROWLENGTH] = 0; }

cout << endl << endl; // Abstand zur nächsten Ausgabe...

}

void draw_window_graph() {

int i,j,zero_point_x,zero_point_y;
long double fieldwidth_x = (xe - xa) / ROWLENGTH;
long double fieldwidth_y = (max - min) / SCREENHEIGHT;

//Nullpunkt auf Bildschirmvertikalen finden...
zero_point_y = classify(0,SCREENHEIGHT-1,min,fieldwidth_y,0.0);
zero_point_x = classify(0,ROWLENGTH-1,xa,fieldwidth_x,0.0);

// Kopfzeile schreiben...
cout << "MAX: " << max << "\t\tMIN: " << min << endl;

for(i=0; i<ROWLENGTH; i++) cout << "-";
cout << endl;

/*Da der Index 0 mit dem minimalen Wert identifizeirt ist,
und die Ausgabe der Zeilen von oben nach unten erfolgt,
muss der Index rückwärts laufen. Damit ist die letzte Zeile
im Bildschirm auch der niedrigste Wert*/
for (i=SCREENHEIGHT-1; i>=0; i--) {

//erst mal aufräumen und dann x- und y-Achse einzeichnen...
for(j=0;j<ROWLENGTH;j++) row[j] = ' ';
if( i == zero_point_y )
for (j=0;j<ROWLENGTH;j++) row[j]='-';

for(j=0; j<ROWLENGTH; j++){

if( zero_point_x == j ) row[j]='|';//y-Achse einzeichnen...

if( classify(0,SCREENHEIGHT-1,min,fieldwidth_y,tab[j]) == i ){
row[j] = '*';
} // <- fkt.-wert einzeichnen

} //ende for j

row[ROWLENGTH] = 0; // Newline schreiben...
cout << row << endl;

}//ende for i

cout << endl << endl; // Abstand zur nächsten Ausgabe...

} //ende fkt.

};

/******************************************************************/

int main() {

cout << "Programm zum Zeichnen von Funktionskurven...." << endl;

Graph obj;
Graph obj2(-2,0.5);

cout << "Ausgabe in vertikaler Richtung..." << endl ;
obj.draw_endless_graph();
cout << "Ausgabe in horizontaler Richtung..." << endl ;
obj.draw_window_graph();

cout << "Ausgabe mit anderem x-Achsenintervall..." << endl;
obj2.draw_endless_graph();
obj2.draw_window_graph();

return 0;

}

Boris Glawe, Aug 25, 2003

2. Kevin GoodsellGuest

Please don't post attachments to non-binary groups, and please do not
give non-standard code as the answer to a question on this group.

-Kevin

Kevin Goodsell, Aug 25, 2003