[Delphi Canvas] Wykres funkcji y = ax + b - co zmienić?

0

Witam!

Mam na formie Image o wymiarach 200 x 200 i dwa okienka edycyjne, do których użytkownik wprowadza parametry a i b. Program ma rysować wykres funkcji y = ax + b. Napisałem taki kod:

procedure TForm1.Button1Click(Sender: TObject);
var a, b, i, x : Integer;
begin
  //Pobranie parametrow
  a := StrToint(Edit1.Text);
  b := StrToInt(Edit2.Text);

  //Rysowanie ukladu wspolrzednych
  With Image1 do
  begin
    Canvas.MoveTo(100, 0);
    Canvas.LineTo(100, 200);
    Canvas.MoveTo(0, 100);
    Canvas.LineTo(200, 100);
  end;

  //Rysowanie wykresu funkcji
  Image1.Canvas.MoveTo(0, 0);
  x := 0;
  for i := 1 to 200 do
  begin
    Image1.Canvas.LineTo(x, a * x + b);
    x := x + 1;
  end;
end;

Problem tkwi w tym, że po narysowaniu układu współrzędnych punkt (0, 0) znajduje się w lewym górnym rogu Imagea, a powinien znajdować się w punkcie (100, 100) (tu bowiem jest graficzny środek układu). Na jednym forum dostałem odpowiedź, żeby do x dodać 100, a od y odjąć 100, więc wyglądałoby to tak: Image1.Canvas.LineTo(x + 100, (a * x + b) - 100);`

Jednak dalej "coś" mi nie pasuje... Może Wy mi pomożecie? Acha, jeszcze jedno pytanie - co polecacie do rysowania takich wykresów - Canvas.Pixels czy Canvas.LineTo? Z góry wielkie dzięki za wszystkie odpowiedzi. Pozdrawiam!

0

Wydaje mi się że ci źle podpowiedzieli .
Jak na moje oko to do y tez trzeba by było dodać 100 a nie odjąć

Image1.Canvas.LineTo(x + 100, (a * x + b) +100);
0
  Image1.Canvas.MoveTo(-1, 100 - f(-101));
  x := -100;
  for i := 0 to 200 do
  begin
    Image1.Canvas.LineTo(i, 100 - f(x));
    x := x + 1;
  end;

Nie sprawdzałem bo nie mam na czym, ale powinno być ok. Jest "100 - wartość" dlatego, że y na ekranie ma odwrotny kierunek niż na układzie współrzędnych. No i specjalnie rysuje poza granicami canvas'a, żeby linie były dociągnięte na końcach.
To był przykład dla dowolnej funkcji f.

Bo żeby narysować funkcję liniową wystarczy połączyć dwa skrajne punkty:

Image1.Canvas.MoveTo(0, 100 - (-100 * a + b));
Image1.Canvas.LineTo(199, 100 - (99 * a + b));
0
x:= -100;
Image1.Canvas.MoveTo(x + 100, 100-(a * x + b));
for x := -99 to 100 do
  begin
    Image1.Canvas.LineTo(x + 100, 100-(a * x + b));
  end;

Dzięki LineTo wykres będzie ciągły. W przypadku użycia Pixels będziesz miał punkty nie stanowiące ciągłego wykresu.

0

ja jeszcze dorzucę

procedure TForm1.Button1Click(Sender: TObject);
var
 a,b : integer;
 x : real;
begin
  //Pobranie parametrow
  a := StrToint(Edit1.Text);
  b := StrToInt(Edit2.Text);

  //Rysowanie ukladu wspolrzednych
  With Image1 do
  begin
    Canvas.MoveTo(100, 0);
    Canvas.LineTo(100, 200);
    Canvas.MoveTo(0, 100);
    Canvas.LineTo(200, 100);
  end;

  //Rysowanie wykresu funkcji

  x := -100;
  repeat

    Image1.Canvas.Pixels[round(x)+100,(round(a * x + b)+100)]:=clblue;

    x := x + 0.01;
  until  (x>100)

end;
0

Dzięki LineTo wykres będzie ciągły. W przypadku użycia Pixels będziesz miał punkty nie stanowiące ciągłego wykresu.

No ja bym mógł się kłócić patrz przykład wyżej :P

0
gość napisał(a)

Dzięki LineTo wykres będzie ciągły. W przypadku użycia Pixels będziesz miał punkty nie stanowiące ciągłego wykresu.

No ja bym mógł się kłócić patrz przykład wyżej :P

Wykres i tak nie będzie ciągły we wszystkich przypadkach, poza tym pętla wykonuje się 2000 razy co całe rozwiązanie kompromituje. Kolejna sprawa to błąd w zapisie powinno być 100-round(a * x + b)

0
AdamPL napisał(a)

Kolejna sprawa to błąd w zapisie powinno być 100-round(a * x + b)
Niby dlaczego ???

Poza tym do narysowania funkcji liniowej potrzebna jest tylko 1 linia a nie 200 czy 2000 !

0
adf88 napisał(a)
AdamPL napisał(a)

Kolejna sprawa to błąd w zapisie powinno być 100-round(a * x + b)
Niby dlaczego ???
Po pierwsze to nie wiem o co do mnie pijesz?! Po drugie w swoim rozwiązaniu też tak podałeś, więc czemu się teraz sam ze sobą nie zgadzasz? Może dlatego, że poprawiłeś swoje rozwiązanie po pojawieniu się mojej odpowiedzi i po prostu bezmyślnie przepisałeś?

adf88 napisał(a)

Poza tym do narysowania funkcji liniowej potrzebna jest tylko 1 linia a nie 200 czy 2000 !
Tu masz 100% racji, aby narysować ten konkretny wykres wystarczyłaby jedna linia. Zarówno 200 czy 2000 wywołań funkcji w tym przypadku jest bardzo nieoptymalne.

0

Nie no nie piję do Ciebie. Pytam tylko dlaczego tak uważasz, bo chce ci uświadomić, że się mylisz. A w swoim rozwiązaniu tak nie podawałem.
Bez urazy, to nie był żaden bulwers :) , przynajmniej nie chciałem, żeby to tak zabrzmiało.

0

a=0
b=0
x=0

a * x + b = 0

Jeżeli środek układu współrzędnych jest na pozycji 100,100 to punkt będący rozwiązaniem powinien się znaleźć w układzie na pozycji (0,0), a na rysunku na pozycji (100,100).

a dla:
a=0
b=2
x=0

a * x + b = 2

Jeżeli środek układu współrzędnych jest na pozycji 100,100 to punkt będący rozwiązaniem powinien się znaleźć w układzie na pozycji (0,2), a na rysunku na pozycji (100,98).

Dlatego właśnie powinno być tak jak napisałem:
100 - (a * x + b)

Bardziej łopatologicznie już się chyba nie da...

0

Ale dlaczego tłumaczysz mi to co ja sam napisałem ?

adf88 napisał(a)

Image1.Canvas.LineTo(i, 100 - f(x));

Ja pytam, po co ten round ?

Aaaa już rozumiem, poprawiałeś zapis "gościa". Na dodatek myślałeś, że "gość" to ja :D Ojojoj sie podziało, a taka prosta funkcja. Jakbym był moderatorem, to bym zostawił tylko pierwsze 4 wypowiedzi, a resztę uciął w pi... Ale nam "gość" namieszał.

0

Ostatecznie zrobiłem to tak:

procedure TForm1.Button1Click(Sender: TObject);
var a, b, i, x, y : Integer;
begin
  //Pobranie parametrow
  a := StrToint(Edit1.Text);
  b := StrToInt(Edit2.Text);

  //Rysowanie ukladu wspolrzednych
  With Image1 do
  begin
    Canvas.MoveTo(100, 0);
    Canvas.LineTo(100, 200);
    Canvas.MoveTo(0, 100);
    Canvas.LineTo(200, 100);
  end;

  //Rysowanie wykresu funkcji
  Image1.Canvas.MoveTo(-1, 201);
  Image1.Canvas.Pen.Color := clRed;
  x := -100;
  REPEAT
  begin
    y := a * x + b;
    Image1.Canvas.LineTo(x + 100, -y + 100);
    x := x + 1;
  end;
  UNTIL (x = 100);
end;

Nie jest chyba idealnie, ale chyba robi co do niego neleży;] Co do tego rounda, to chodzi o to, że jeśli wynik to liczba rzeczywista a nie całkowita, to zaokrągla do całkowitej, bo przecież nie można zamalować połowy pixela:]

0

I po co dalej tą pętle męczysz. Przecież pisałem 2 razy (dotego AdamPL też pisłał), że wsytarczy

Image1.Canvas.MoveTo(0, 100 - (-100 * a + b));
Image1.Canvas.LineTo(199, 100 - (99 * a + b));

[glowa]

0

Panowie zamiast odejmować współrzędne i coś kombinować proponuję użyć

 SetViewportOrgEx(Image1.Canvas.Handle, Image1.Width div 2, Image1.Height div 2, nil); // określenie początku układu wspólrzędnych 
SetMapMode(Image1.Canvas.Handle, MM_LOENGLISH);  //odwrócenie osi na sposób matematyczny
{ z powrotem MM_TEXT}

i już mamy właściwy układ współrzędnych ;-P

0

@Piotrekdp - tyle, że to jest w api.

gość napisał(a)

x := -100;
repeat

Image1.Canvas.Pixels[round(x)+100,(round(a * x + b)+100)]:=clblue;

x := x + 0.01;

until (x>100)

Pierwszy round jest niepotrzebny ale drugi już jest konieczny. Przecież tutaj przesuwasz się o 0,01, więc wynik a * x + b będzie liczbą zmiennoprzecinkową. Pisząc, że sam sobie zaprzeczasz miałem na myśli to, że sam zapisałeś 100-(a * x + b) nie wiedziałem, że do tego rounda masz waty.

1 użytkowników online, w tym zalogowanych: 0, gości: 1