In Turbo-CPP sind die Abmessungen und die Ausrichtung der Image-Komponente vorgegeben (0,0,Image.Width,Image.Height). Um die Berechnung des Funktionsgraphen zu vereinfachen, wird neben dem Bildbereich ein Weltbereich angenommen. Ein Weltpunkt WP hat die Weltkoordinaten WP.x, WP.y und der zugehörige Bildpunkt BP hat die Bildkoordinaten BP.x, BP.y. Der Nullpunkt der Bildkoordinaten liegt links oben, der Nullpunkt der Weltkoordinaten zunächst im Mittelpunkt des Fensters. Ein Weltpunkt WP ist durch die Klasse WPunkt definiert:
class WPunkt //Weltpunkt (0/0) in Mitte {double x,y; };
Ein Bildpunkt BP ist durch folgende Klasse definiert:
class BPunkt //Bildpunkt {int x,y; };
In der Umrechnung von Welt- in Bildkoordinaten und umgekehrt soll zunächst der Zoomfaktor eingerechnet werden.
Im Programm soll dies durch die Werte zweier Trackbars oder Scrollbars realisiert werden.
Hier werden der Einfachheit halber die Bezeichnungen zoomhz und zoomvt verwendet. Der Wert von zoomhz ist genau die Anzahl der Pixel im Bildbereich, die der Länge 1 auf der x-Achse im Weltbereich entsprechen (analog für zoomvt).
Es ergeben sich somit folgende geometrische Verhältnisse:
zoomhz : 1 = (BP.x - Image→Width/2) : WP.x
zoomvt : 1 = (Image→Height/2 - BP.y) : WP.y
Somit ergibt sich folgender Zusammenhang, um die Bildkoordinaten (BP.x/BP.y) aus den Weltkoordinaten (WP.x/WP.y) zu berechnen:
BP.x :=zoomhz*WP.x +Image→Width/2)
BP.y := (Image→Height/2 -zoomvt*WP.y)
Analog kann man umgekehrt die Weltkoordinaten (WP.x/WP.y) aus den Bildkoordinaten (BP.x/BP.y) berechnen.
CBPunkt WeltZuBild(double x, double y) { //rechnet Weltkoordinaten in Bildkoordinaten um CBPunkt b; b.x=(int) (zoomhz*x+Form1->Image1->Width/2)+0.5; //runden auf Ganze b.y=(int) (Form1->Image1->Height/2-zoomvt*y)+0.5; return b; } CWPunkt BildZuWelt(int x, int y) { //rechnet Bild in Weltkoordinaten um CWPunkt w; w.x=round((double)(x-Form1->Image1->Width/2)/zoomhz); w.y=round((double)(Form1->Image1->Height/2-y)/zoomvt); return w; }
//--------------------------------------------------------------------------- #include <vcl.h> #include <math.h> //für die Wurzel sqrt() #include <cmath> //für abs() #include <algorithm> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; TPoint punkt1=Point(60, 20), punkt2=Point(80,80); int zoomhz=30,zoomvt=30, updohz=0,updovt=0; double round(double x) { x=(int)(x*100+0.5); x=(double)(x/100); return x; } class CBPunkt //Klasse Bildpunkt { public: int x,y; }; class CWPunkt //Klasse Weltpunkt { public: double x,y; }; CWPunkt wp; CBPunkt bp; CBPunkt WeltZuBild(double x, double y) { //rechnet Weltkoordinaten in Bildkoordinaten um CBPunkt b; b.x=(int) (zoomhz*x+Form1->Image1->Width/2)-updohz+0.5; //runden auf Ganze b.y=(int) (Form1->Image1->Height/2-zoomvt*y)+updovt+0.5; return b; } CWPunkt BildZuWelt(int x, int y) { //rechnet Bild in Weltkoordinaten um CWPunkt w; w.x=round((double)(x-Form1->Image1->Width/2+updohz)/zoomhz); w.y=round((double)(Form1->Image1->Height/2-y+updovt)/zoomvt); return w; } class CQuadFunkt { public: double a, b, c; double f(double x) //Methode (Funktionswert) { return a*x*x+b*x+c; } double diskr() { return b*b-4*a*c; } double nst1() { return (-b+sqrt(diskr()))/(2*a); } double nst2() { return (-b-sqrt(diskr()))/(2*a); } double extremum() { return -b/(2*a); } void plot() { double diff; CWPunkt wpmin, wpmax, wp; CBPunkt bp; wpmin=BildZuWelt(0,Form1->Image1->Height); //li unten wpmax=BildZuWelt(Form1->Image1->Width,0); //re oben //diff ist der Abstand im Weltbereich von Pixel zu Pixel diff=(wpmax.x-wpmin.x)/Form1->Image1->Width; wp.x=wpmin.x; wp.y=f(wp.x); //1. Weltpunkt ganz links bp=WeltZuBild(wp.x,wp.y); // 1. Bildpunkt ganz links Form1->Image1->Canvas->MoveTo(bp.x,bp.y); do { wp.x=wp.x+diff; //x-Koordinate des nächsten Weltpunkts wp.y=f(wp.x); bp=WeltZuBild(wp.x,wp.y); Form1->Image1->Canvas->LineTo(bp.x,bp.y); } while (wp.x<=wpmax.x); } }; CQuadFunkt quad; //globale Variable, welche die quadratische Funktion und ihre //Eigenschaften representiert class CLinFunkt { public: double k, d; double f(double x) //Methode (Funktionswert) { return k*x+d; } double nst() { return (-d/k); } void plot() { CWPunkt wpmin, wpmax; CBPunkt bp; wpmin=BildZuWelt(0,Form1->Image1->Height); //li unten wpmax=BildZuWelt(Form1->Image1->Width,0); //re oben wp.x=wpmin.x; wp.y=f(wp.x); //1. Weltpunkt ganz links bp=WeltZuBild(wp.x,wp.y); // 1. Bildpunkt ganz links Form1->Image1->Canvas->MoveTo(bp.x,bp.y); wp.x=wpmax.x; //Weltpunkt ganz rechts wp.y=f(wp.x); bp=WeltZuBild(wp.x,wp.y); Form1->Image1->Canvas->LineTo(bp.x,bp.y); } }; CLinFunkt lin; //globale Variable, welche die lineare Funktion und ihre //Eigenschaften representiert void plotkoordkr() { Form1->Image1->Canvas->Brush->Color=clWhite; Form1->Image1->Canvas->FillRect(Form1->Image1->Canvas->ClipRect); CWPunkt wpmin,wpmax; //Hilfsweltpunkte //Zwei Eckpunkte des Bildbereichs wpmin=BildZuWelt(0,Form1->Image1->Height); //li unten wpmax=BildZuWelt(Form1->Image1->Width,0); //re oben //x-Koordinate CBPunkt bph1,bph2; //Hilfspunkte bph1=WeltZuBild(wpmin.x,0); //Anfangspkt x-Koord. im Bild bph2=WeltZuBild(wpmax.x,0); //Endpkt x-Koord. im Bild Form1->Image1->Canvas->Pen->Color=clBlack; Form1->Image1->Canvas->MoveTo(bph1.x-2,bph1.y); Form1->Image1->Canvas->LineTo(bph2.x+2,bph2.y); //y-Koordinate bph1=WeltZuBild(0,wpmin.y); //Anfangspkt x-Koord. im Bild bph2=WeltZuBild(0,wpmax.y); //Endpkt x-Koord. im Bild Form1->Image1->Canvas->MoveTo(bph1.x,bph1.y+2); Form1->Image1->Canvas->LineTo(bph2.x,bph2.y-2); //Stricherl auf x-Achse for (int i=(int)(wpmin.x);i<=(int)(wpmax.x) ;i++ ) { bph1=WeltZuBild(i,0); Form1->Image1->Canvas->MoveTo(bph1.x,bph1.y-3); Form1->Image1->Canvas->LineTo(bph1.x,bph1.y+3); } //Stricherl auf y-Achse for (int i=(int)(wpmin.y);i<=(int)(wpmax.y) ;i++ ) { bph1=WeltZuBild(0,i); Form1->Image1->Canvas->MoveTo(bph1.x-3,bph1.y); Form1->Image1->Canvas->LineTo(bph1.x+3,bph1.y); } //Raster anzeigen if (Form1->CheckBoxRaster->Checked) { for (int i=(int)(wpmin.x);i<=(int)(wpmax.x) ;i++ ) { for (int j=(int)(wpmin.y);j<=(int)(wpmax.y) ;j++ ) { bph1=WeltZuBild(i,j); Form1->Image1->Canvas->Pixels[bph1.x][bph1.y]=clBlack; } } } //Achsenbeschriftung anzeigen //x-Koord bph1=WeltZuBild(wpmax.x,0); Form1->Image1->Canvas->TextOutA(bph1.x-10,bph1.y+5,"x"); //y-Koord bph1=WeltZuBild(0,wpmax.y); Form1->Image1->Canvas->TextOutA(bph1.x-12,bph1.y,"y"); //Zahlenwerte auf Achse 1er bph1=WeltZuBild(1,0); Form1->Image1->Canvas->TextOutA(bph1.x-2,bph1.y+5,"1"); bph1=WeltZuBild(-1,0); Form1->Image1->Canvas->TextOutA(bph1.x-4,bph1.y+5,"-1"); bph1=WeltZuBild(0,1); Form1->Image1->Canvas->TextOutA(bph1.x-10,bph1.y-7,"1"); bph1=WeltZuBild(0,-1); Form1->Image1->Canvas->TextOutA(bph1.x-13,bph1.y-7,"-1"); //Zahlenwerte 5er //x-Achse + for (int i=5;(i<=wpmax.x) ||(i<=wpmin.x*(-1))||(i<=wpmin.y*(-1))||(i<=wpmax.y) ;i=i+5 ) { bph1=WeltZuBild(i,0); Form1->Image1->Canvas->TextOutA(bph1.x-3,bph1.y+5,IntToStr(i)); bph1=WeltZuBild(-i,0); Form1->Image1->Canvas->TextOutA(bph1.x-7,bph1.y+5,IntToStr(-i)); bph1=WeltZuBild(0,i); Form1->Image1->Canvas->TextOutA(bph1.x-12,bph1.y-7,IntToStr(i)); bph1=WeltZuBild(0,-i); Form1->Image1->Canvas->TextOutA(bph1.x-15,bph1.y-7,IntToStr(-i)); } } void FunktEigensch() { if (Form1->RadioButtonquad->Checked) { Form1->GroupBox2->Caption="Quadratische Funktion"; Form1->LabelExtremum->Caption="Extremum:"; if (quad.diskr()<0) { Form1->LabelNSTAnzahl->Caption="Es gibt keine Nullstelle!"; Form1->LabelN1->Caption=""; Form1->LabelN2->Caption=""; } else if (quad.diskr()==0) { Form1->LabelNSTAnzahl->Caption="Es gibt genau eine (doppelte) Nullstelle!"; Form1->LabelN1->Caption="x = "+ FloatToStr(quad.nst1()); Form1->LabelN2->Caption=""; } else if (quad.diskr()>0) { Form1->LabelNSTAnzahl->Caption="Es gibt zwei Nullstellen!"; Form1->LabelN1->Caption="x1 = "+ FloatToStr(quad.nst1()); Form1->LabelN2->Caption="x2 = "+ FloatToStr(quad.nst2()); } if (quad.a>0) { Form1->LabelEx->Caption="Tiefpunkt T("+FloatToStr(quad.extremum())+"/"+FloatToStr(quad.f(quad.extremum()))+")"; } else Form1->LabelEx->Caption="Hochpunkt H("+FloatToStr(quad.extremum())+"/"+FloatToStr(quad.f(quad.extremum()))+")"; } else { Form1->GroupBox2->Caption="Lineare Funktion"; if (lin.k!=0) { Form1->LabelNSTAnzahl->Caption="Es gibt eine Nullstelle!"; Form1->LabelN1->Caption="x = "+ FloatToStr(lin.nst()); Form1->LabelN2->Caption=""; } else { if (lin.d=0) { Form1->LabelNSTAnzahl->Caption="Es gibt unendlich viele Nullstellen!"; } else { Form1->LabelNSTAnzahl->Caption="Es gibt keine Nullstelle!"; } Form1->LabelN1->Caption=""; Form1->LabelN2->Caption=""; } Form1->LabelEx->Caption=""; Form1->LabelExtremum->Caption=""; } } void plotfunktion() { plotkoordkr(); if (Form1->RadioButtonquad->Checked) { quad.a=StrToFloat(Form1->Edita->Text); quad.b=StrToFloat(Form1->Editb->Text); quad.c=StrToFloat(Form1->Editc->Text); quad.plot(); } else { lin.k=StrToFloat(Form1->Editk->Text); lin.d=StrToFloat(Form1->Editd->Text); lin.plot(); } FunktEigensch(); } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { CWPunkt w; w=BildZuWelt(X,Y); Label1->Caption=FloatToStr(w.x); Label2->Caption=FloatToStr(w.y); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { plotfunktion(); FunktEigensch(); } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBar1Change(TObject *Sender) { zoomhz=TrackBar1->Position; plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBar2Change(TObject *Sender) { zoomvt=TrackBar2->Position; plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBoxRasterClick(TObject *Sender) { plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::UpDownhzClick(TObject *Sender, TUDBtnType Button) { updohz=UpDownhz->Position; plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::UpDownvtClick(TObject *Sender, TUDBtnType Button) { updovt=UpDownvt->Position; plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::EditaExit(TObject *Sender) { if (Edita->Text==""||Edita->Text=="0") { Edita->Text="1"; } } //--------------------------------------------------------------------------- void __fastcall TForm1::EditbKeyPress(TObject *Sender, char &Key) { if (!((Key>='0')&&(Key<='9')||(Key==',')||(Key==8)||(Key=='-'))) {Key=0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::EditcKeyPress(TObject *Sender, char &Key) { if (!((Key>='0')&&(Key<='9')||(Key==',')||(Key==8)||(Key=='-'))) {Key=0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::EditkKeyPress(TObject *Sender, char &Key) { if (!((Key>='0')&&(Key<='9')||(Key==',')||(Key==8)||(Key=='-'))) {Key=0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::EditdKeyPress(TObject *Sender, char &Key) { if (!((Key>='0')&&(Key<='9')||(Key==',')||(Key==8)||(Key=='-'))) {Key=0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::EditaKeyPress(TObject *Sender, char &Key) { if (!((Key>='0')&&(Key<='9')||(Key==',')||(Key==8)||(Key=='-'))) {Key=0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::RadioButtonquadClick(TObject *Sender) { plotfunktion(); } //--------------------------------------------------------------------------- void __fastcall TForm1::RadioButtonlinClick(TObject *Sender) { plotfunktion(); } //---------------------------------------------------------------------------