Entwickler-Ecke

Multimedia / Grafik - Parabeln zeichnen


wayne123 - Mo 17.01.11 20:39
Titel: Parabeln zeichnen
Ok, jetzt weiß ich, wie man Potenzen in Delphi macht, aber noch bin ich mit den Parabeln nicht so weit. Jetzt will ich erstmal nur mit ^2 rechnen, hab da aber trotzdem ein Problem. Wenn ich negative Werte eingebe, kommt überhaupt keine Parabel und manchmal ist MoveTo an der falschen Stelle. Ich hab mit der Formel a*(x-d)^2+e gerechnet, gibt es da eig. eine bessere Formel für Parabeln?
Ich hoffe mal das funktioniert

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:
unit Unit2Parabeln;

interface

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

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

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var x,y: integer;
a,d,e: extended;
begin
Canvas.MoveTo(0,Clientheight div 2);
Canvas.LineTo(Clientwidth,Clientheight div 2);
Canvas.MoveTo(Clientwidth div 2,0);
Canvas.LineTo(Clientwidth div 2,Clientheight);

a:= StrToFloat(Edit1.Text);
d:= StrToFloat(Edit2.Text);
e:= StrToFloat(Edit3.Text);
Canvas.MoveTo(0,round(-a*(0-d)*(0-d)-e));
for x:=0 to Clientheight do
begin
y:= round(-a*((x-d)*(x-d))-e);
Canvas.LineTo(x+Clientwidth div 2,y+ Clientheight div 2)
end;
end;
end.



Moderiert von user profile iconMartok: Topic aus Sonstiges (Delphi) verschoben am Mo 17.01.2011 um 21:32


Tranx - Mo 17.01.11 21:05

Du hast da einen kleinen Fehler gemacht:

Die x-Werte fangen erst bei 0 an: Wenn Du schreibst:

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:
 procedure TForm1.Button1Click(Sender: TObject);
var
  x, y: integer;
  a, d, e: extended;
begin
  Canvas.MoveTo(0, Clientheight div 2);
  Canvas.LineTo(Clientwidth, Clientheight div 2);
  Canvas.MoveTo(Clientwidth div 20);
  Canvas.LineTo(Clientwidth div 2, Clientheight);

  a := StrToFloat(Edit1.Text);
  d := StrToFloat(Edit2.Text);
  e := StrToFloat(Edit3.Text);

  for x := -ClientWidth div 2  to ClientWidth div 2 do
  begin
    y := round(-a * ((x - d) * (x - d)) - e);
    if x = -ClientWidth div 2 then
      Canvas.MoveTo(0,y + ClientHeight div 2)
    else
      Canvas.LineTo(x + Clientwidth div 2, y + Clientheight div 2)
  end;
end;


dann geht das! Ich habe auch die Startposition gleich mit in die Schleife genommen. Ist sicher nicht unbedingt notwendig, aber Du brauchst dann y nur einmal zu berechnen.


wayne123 - Mo 17.01.11 21:13

ahh, danke, dass hatte ich auch schon bei den Geraden verpennt. Und wenn ich jetzt mit Power oder exp noch eine veränderbare Hochzahl reinbringen möchte, müsste ich da viel ändern? Wenn ja, dann würd ich nämlich lieber mit einem neuem Projekt anfangen und dann irgendwie so ne Formel, wie: y=a*x^f+b*x^g+c. Aber das dürfte ja viel komplizierter werden.

Wie y nur einmal berechnen? Sieht für mich komplizierter aus, würde sich denn da irgendein Vorteil ergeben, für den es sich lohnen würde, das eher so zu machen, weil ich ja gerade es endlich so geschafft habe.


Tranx - Di 18.01.11 09:12

Am Besten, Du gehst wie folgt vor:

Du schreibst eine Funktion, in der Du die zu plottende Funktion schreibst. Dann ist das einfacher zu verwalten.

Außerdem habe ich zwei Funktionen definiert Transform und Retransform. Mit Transform wandelst Du einen Wert in eine Position im Plot um und mit Retransform umgekehrt eine Plotposition in einen Wert.

Was soll das? Nun, ganz einfach, wenn Du a) nicht den ganzen Formularbereich (Canvas) übermalen willst, musst Du den Plot eingrenzen. Das ist noch klar. Aber was ist, wenn Du Grafiken zeichnen willst, die schnell große y-Werte annehmen (y = x^7 z.B.). Dann müsstest Du jedesmal das Programm kompilieren, um den Graph dann zu zeichnen. So könntest Du einfach zusätzliche Editfelder einfügen, in denen Du die Min- und Max-Werte der Koordinatenachsen eingibst und dann die Funktion neu zeichnest, ohne gleich das Programm zu kompilieren.

Außerdem habe ich Dir hier noch ein kleines Beispiel gezeigt, was man mit Delphi so alles treiben kann: überladene Funktionen z.B.

Wenn Du Funktionen mit vorher nicht bekannten Anzahlen von Parametern, z.B.

y = ax^4 + bx^3 + cx^2 + dx + e zeichen willst und gleichzeitig nur ax^2 + bx + c, dann lohnt es sich, darüber nachzudenken:

yWert wäre im Fall 1: yWert := f(x, [a,b,c,d,e], [4,3,2,1,0]) und im zweiten Fall yWert := f(x, [a,b,c], [2,1,0])

Du benötigst dann nicht mehr eine Neukompilierung, wenn Du eine kompliziertere oder weniger komplizierte Funktion wählst. Du solltest aber in jedem Fall beiden Arrays gleich viele Parameter zuordnen.

Wegen der möglichen fehlenden Wertebereiche (-1^0,5 ist im Zahlenraum der einfachen Zahlen nicht definiert) bei negativen x-Werten für die Funktion Power(x,n) habe ich mich auf Intpower beschränkt, weil diese Funktion keinen eingeschränkten Wertebereich hat.


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:
unit GraphUnit;

interface

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

var
  nf : extended = 4.0;
  ng : extended = 1.5;
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

function Transform(Value, Vmin, Vmax : extended; MinPos, MaxPos : integer) : integer;
function Retransform(Value : integer; Vmin, Vmax : extended; MinPos, MaxPos : integer) : extended;

function f(x, a, b, c : extended) : extended; overload;
function f(x : extended; a : array of extended; n : array of integer) : extended; overload;

implementation

{$R *.DFM}

function f(x : extended; a : array of extended; n : array of integer) : extended;
var
  w : extended;
  i : integer;
begin
  w := 0.0;
  for i := 0 to high(a) do
  begin
    w := w + a[i]*IntPower(x,n[i]);
  end;
  Result := w;
end;

function f(x, a, b, c : extended) : extended;

begin
 Result := a * intPower(x, 3) + b * intPower(x, 2) + c;
end;



function Transform(Value, Vmin, Vmax : extended; MinPos, MaxPos : integer) : integer;
begin
  Result := round((Value - Vmin)/(Vmax - Vmin)*(MaxPos - MinPos))+MinPos;
end;

function Retransform(Value : integer; Vmin, Vmax : extended; MinPos, MaxPos : integer) : extended;
begin

  Result := ((Value - MinPos)/(MaxPos - MinPos)*(Vmax - Vmin))+Vmin;;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x, y: integer;
  xW, yW, a, d, e: extended;
  xMinPos, xMaxPos, yMinPos, yMaxPos : integer;
const
  ymin : extended = -60.0;
  ymax : extended = 60.0;
  xmin : extended = -4.0;
  xmax : extended = 4.0;
begin
  xMinPos := ClientWidth div 8;
  yMinPos := ClientHeight - ClientHeight div 5;
  xMaxPos := ClientWidth - ClientWidth div 8;
  yMaxPos := 0;
  
  a := StrToFloat(Edit1.Text);
  d := StrToFloat(Edit2.Text);
  e := StrToFloat(Edit3.Text);

  for x := xMinPos to xMaxPos do
  begin
    xW := RetransForm(x, xmin, xmax, xMinPos, xMaxPos);
//    yW := f(xW, a, d, e);
    yW := f(xW, [a, d, e, 4.0], [3210]);
    y := Transform(yW, ymin, ymax, yMinPos, yMaxPos);

    if x = xMinPos then
      Canvas.MoveTo(x,y)
    else
      Canvas.LineTo(x,y);
  end;
  y := Transform(0.0, ymin, ymax, yMinPos, yMaxPos);
  x := Transform(0.0, xmin, xmax, xMinPos, xMaxPos);
  Canvas.MoveTo(xMinPos, y);
  Canvas.LineTo(xMaxPos, y);
  Canvas.MoveTo(x, yMinPos);
  Canvas.LineTo(x, yMaxPos);
end;

end.


wayne123 - Di 18.01.11 16:14

Kannst du mir das irgendwie als Datei geben, damit ich mir das angucken kann? Ich werds nicht einfach so benutzen, sondern will mir das wirklich angucken, damit ich das verstehe, weil so versteh ich das noch nicht ganz.