====== Funktionenplotter ======
===== Theoretische Überlegungen =====
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:
{{:inf:inf8bi_201112:wiederholung_maturastoff:bildbereich1.gif|}} {{:inf:inf8bi_201112:wiederholung_maturastoff:weltbereich1.gif|}}
''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;
}
===== Programmcode =====
//---------------------------------------------------------------------------
#include
#include //für die Wurzel sqrt()
#include //für abs()
#include
#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();
}
//---------------------------------------------------------------------------