Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - funktionsplotter mit canvas


huuuuuh - Mo 07.04.08 18:03
Titel: funktionsplotter mit canvas
wir ham in der schule die aufgabe gekriegt nen kleinen funktionsplotter mit canvas zu schreiben
nach der allgemeinen quadratischen funktions-formel y = ax² + bx + c
hab da jetz diesen quelltext

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
procedure TForm1.Button1Click(Sender: TObject); //Koordinatensystem mit Beschriftung - Zum besseren Verständnis
var xbes,ybes : integer;
    beschriftung:integer;
begin
 with canvas do
  Begin
   moveto(200,250);
   Lineto(700,250);
   moveto(450,50);
   lineto(450,450);
   textout(450-3,250-3,'0');
   xbes:=200;
   beschriftung:=-10;
    repeat
     if not (beschriftung=0then textout(xbes-2,252, inttostr(beschriftung));
     xbes:=xbes+25;
     beschriftung:=beschriftung+1;
    until xbes>700;
   beschriftung:=10;
   ybes:=45;
    repeat
     if not (beschriftung=0then textout(440,ybes, inttostr(beschriftung));
     ybes:=ybes+20;
     beschriftung:=beschriftung-1;
    until ybes>450;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);  //Parabel soll gezeichnet werden
VAR x,y,a,b,c:Real;
begin
 a:=strtofloat(edit1.Text);
 b:=strtofloat(edit2.Text)+25;
 c:=strtofloat(edit3.Text)+20;
 x:=strtofloat(edit4.Text);
 y:=(a*x*a*x+b*x+c)+250;
 x:=x+450;
 if y>screen.DesktopHeight then y := form1.Height+1;
 canvas.moveto(round(X),round(Y));
 x:=x-450;
 x:=x+0.1;
  Repeat
   y:=(a*x*a*x+b*x+c)+250;
   x:=x+450;
   canvas.lineto(round(X),round(Y));
   x:=x-450;
   x:=x+0.1;
  Until x >1000;
end;


Nun das programm zeichnet mir teile von parabeln, es soll aber eine ganze parabel zeichnen
Was mach ich falsch???


huuuuuh - Mi 09.04.08 14:13

keine ideen?


Christian S. - Mi 09.04.08 14:17

Welche Teile werden denn gezeichnet?


huuuuuh - Mi 09.04.08 15:52

ich häng die exe mal an...


Christian S. - Mi 09.04.08 16:05

Folgende Probleme sehe ich:

1. Du zeichnest zwar die Achsen so, dass eine Einheit = 25 Pixel sind, Du zeichnest den Graphen aber nicht entsprechend, dort ist eine Einheit = 1 Pixel

2. Du berechnest den Graphen a²x²+bx+c, Du quadrierst das a also auch mit.

3. Die Eingabe von x verwirrt, denn das ist ja die Laufvariable. Die sollte halt von links nach rechts laufen, über den Bereich wo auch die Skala ist

4. Das hier:

Delphi-Quelltext
1:
2:
3:
   x:=x+450;
   canvas.lineto(round(X),round(Y));
   x:=x-450;

würde ich so schreiben:

Delphi-Quelltext
1:
canvas.lineto(round(X+450),round(Y));                    

Das ist übersichtlicher und kürzer. In einem späteren Schritt solltest Du die 450 variabel machen (z.B. von der Fenstergröße abhängig), aber ein Schritt nach den anderen ;-)

5. Der Graph wird falsch rum gezeichnet, weil das Koordinatensystem in Delphi umgedreht ist.


huuuuuh - Do 10.04.08 14:02

so hab jetz diesen quelltext:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject); //Koordinatensystem mit Beschriftung
var xbes,ybes : integer;
    beschriftung:integer;
begin
with canvas do
Begin
moveto(200,250);
Lineto(700,250);
moveto(450,50);
lineto(450,450);
textout(450-3,250-3,'0');
xbes:=200;
beschriftung:=-10;
repeat
if not (beschriftung=0then textout(xbes-2,252, inttostr(beschriftung));
xbes:=xbes+25;
beschriftung:=beschriftung+1;
until xbes>700;
beschriftung:=10;
ybes:=45;
repeat
if not (beschriftung=0then textout(440,ybes, inttostr(beschriftung));
ybes:=ybes+20;
beschriftung:=beschriftung-1;
until ybes>450;
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
VAR x,y,a,b,c:Real;
xkor: real;
begin
a:=-strtofloat(edit1.Text);
b:=strtofloat(edit2.Text)*25;
c:=strtofloat(edit3.Text)*20;
x:=-10;
x:=x*25;
xkor:=x;
y:=((a*x*x+b*x+c))*20;
if y>form1.Height then y := form1.Height+1;
canvas.moveto(round(x+450),round(y+250));
x:=x+0.1;
Repeat
y:=((a*x*x+b*x+c))*20;
canvas.lineto(round(X+450),round(Y+250));
x:=x+0.1;
Until x >-xkor;
end;

end.


krig das mit der einheit aber noch nich hin


Christian S. - Fr 11.04.08 17:21

Hm. Irgendwie sieht das für mich aus, als hättest Du mit dem Salzstreuer ein paar "*20" und "*25" da rein gemacht, ein wirkliches System erkenne ich da nicht. Im Prinzip ist das doch ein einfacher Dreisatz:

1 Einheit = 25 Pixel
x Einheiten = ? Pixel

Und dann das entsprechende x (oder auch y) eingesetzt. Du musst nur einmal pro Dimension multiplizieren / skalieren. Und die Skalierung zur Darstellung und nicht zur eigentlich berechnung gehört, sollte die auch bei LineTo stattfinden.



//edit: Bitte formatiere Deinen Quelltext, das ist sonst sehr mühsam zu lesen.


huuuuuh - Fr 11.04.08 22:02

so habs jetz - funktioniert jetz alles - auch mit der einheit


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure onclosequery(Sender: TObject; var CanClose: Boolean);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject); //Koordinatensystem mit Beschriftung
var xbes,ybes : integer;
    beschriftung:integer;
begin
 with canvas do
  Begin
   moveto(200,250);
   Lineto(700,250);
   moveto(450,50);
   lineto(450,450);
   textout(450-3,250-3,'0');
   xbes:=200;
   beschriftung:=-10;
   repeat
    if not (beschriftung=0then textout(xbes-2,252, inttostr(beschriftung));
    xbes:=xbes+25;
    beschriftung:=beschriftung+1;
   until xbes>700;
   beschriftung:=10;
   ybes:=45;
   repeat
    if not (beschriftung=0then textout(440,ybes, inttostr(beschriftung));
    ybes:=ybes+20;
    beschriftung:=beschriftung-1;
   until ybes>450;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
VAR x,y,a,b,c:Real;
xkor: real;
begin
 try
 a:=-strtofloat(edit1.Text);
 b:=strtofloat(edit2.Text)*25;
 c:=-strtofloat(edit3.Text)*20;
 except
   a:=-1;
   b:=0;
   c:=0;
 end;
 x:=-100;
 xkor:=x;
 y:=((a*x*x));
 x:=x*25;
 y:=y*20;
 canvas.moveto(round(x+450+b),round(y+250+c));
 x:=x/25;
 x:=x+0.1;
 Repeat
  y:=((a*x*x));
  x:=x*25;
  y:=y*20;
  canvas.lineto(round(X+450+b),round(Y+250+c));
  x:=x/25;
  x:=x+0.1;
 Until x >-xkor;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
close;
end;

procedure TForm1.onclosequery(Sender: TObject; var CanClose: Boolean);
begin
if Application.MessageBox('Möchten sie das Programm wirklich beenden?','Beenden'4+32)=6 then canclose:=true else canclose:=false;
end;

end.


SmileySN - Sa 12.04.08 01:26

Hier habe ich das ganze mal etwas lesbarer mit Variablen für die X- und Y-Offsets und Steps gemacht.
Jetzt fehlt nur noch das Clipping, also das ausblenden und nicht zeichnen aller Punkte die nicht in das Koordinatensystem hineinpassen.
Dann könnte man die Zeichnung auch noch auf einem Panel machen, das ist dann frei verschiebbar.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
Unit Main;

Interface

Uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

Type
  TForm1 = Class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Procedure FormCreate(Sender: TObject);
//    procedure Button3Click(Sender: TObject);
    Procedure Button2Click(Sender: TObject);
    Procedure Button1Click(Sender: TObject);

    Procedure onclosequery(Sender: TObject; Var CanClose: Boolean);
  Private
    { Private-Deklarationen }
  Public
    { Public-Deklarationen }
  End;

Var
  Form1: TForm1;
  XMin, XMax, YMin, YMax, XOffset, YOffset: Integer;
  XBegin, XEnde, YBegin, YEnde, XMitte, YMitte: Integer;
  XStep,YStep:Integer;

Implementation

{$R *.dfm}

Procedure TForm1.FormCreate(Sender: TObject);
Begin
  Edit1.Text := '2';
  Edit2.Text := '1';
  Edit3.Text := '-10';
  XOffset := 200;
  YOffset := 100;
  XMin := 0;
  XMax := 500;
  YMin := 0;
  YMax := 400;
  XBegin := XOffset + XMin;
  YBegin := YOffset + YMin;
  YMitte := YOffset + YMax Div 2;
  XEnde := XOffset + XMax;
  YEnde := YOffset + YMax;
  XMitte := XOffset + XMax Div 2;
  XStep := 25;
  YStep := 20;
End;

Procedure TForm1.Button1Click(Sender: TObject); //Koordinatensystem mit Beschriftung
Var
  xbes, ybes: Integer;
  beschriftung: Integer;
Begin
  With canvas Do
    Begin
      moveto(XBegin, YMitte); // X-Achse Begin aufsetzen
      Lineto(XEnde, YMitte);  // X-Achse zeichnen
      moveto(XMitte, YBegin); // Y-Achse Begin aufsetzen
      Lineto(XMitte, YEnde);  // Y-Achse zeichnen
   // textout(XMitte-3,YMitte-3,'0');
      xbes := XBegin;
      beschriftung := -10;
      Repeat                  // Beschriftung der X-Achse
        If Not (beschriftung = 0Then textout(xbes - 2, YMitte + 2, inttostr(beschriftung));
        xbes := xbes + XStep;
        beschriftung := beschriftung + 1;
      Until xbes > XEnde;

      beschriftung := 10;
      ybes := YBegin;
      Repeat
        If Not (beschriftung = 0Then textout(XMitte+3, ybes-6, inttostr(beschriftung));
        ybes := ybes + YStep;
        beschriftung := beschriftung - 1;
      Until ybes > YEnde;
    End;
End;

Procedure TForm1.Button2Click(Sender: TObject);
Var
  x, y, a, b, c: Real;
  xkor: Real;
Begin
  Try
    a := -strtofloat(Edit1.Text);
    b := strtofloat(Edit2.Text) * XStep;
    c := -strtofloat(Edit3.Text) * YStep;
  Except
    a := -1;
    b := 0;
    c := 0;
  End;
  x := -100;
  xkor := x;
  y := ((a * x * x));
  x := x * XStep;
  y := y * XStep;
  canvas.moveto(round(x + XMitte + b), round(y + YMitte + c));
  x := x / XStep;
  x := x + 0.1;
  Repeat
    y := ((a * x * x));
    x := x * XStep ;
    y := y * YStep ;
    canvas.Lineto(round(x+ XMitte + b), round(y+YMitte + c));
    x := x / XStep;
    x := x + 0.1;
  Until (x > -Xkor);
End;

Procedure TForm1.onclosequery(Sender: TObject; Var CanClose: Boolean);
Begin
  If Application.MessageBox('Möchten sie das Programm wirklich beenden?''Beenden'4 + 32) = 6 Then
    CanClose := true
  Else
    CanClose := False;
End;

End.