Wykres trójmianu a skala

0

Witam, ucze sie właśnie C# i mam taki problem. Chciałem narysować wykres trójmianu kwadratowego (parabole). Jakoś mi sie to udało ale problem pojawia sie jak chce żeby można było dynamicznie zmieniać skale wykresu.

Mój kod wygląda tak:

        private void rysuj_wykres()
        {
            Bitmap bmp = new Bitmap(450, 450);
            Graphics g = Graphics.FromImage(bmp);
            Pen p = new Pen(Color.Black, 1);

            //XOY
            g.DrawLine(p, 0, 225, 450, 225);
            g.DrawLine(p, 225, 0, 225, 450);

            //strzałki
            g.DrawLine(p, 220, 5, 225, 0);
            g.DrawLine(p, 230, 5, 225, 0);
            g.DrawLine(p, 445, 220, 450, 225);
            g.DrawLine(p, 445, 230, 450, 225);

            //podziałka
            for (x = 225; x < 450; x = x + skala)
            {
                g.DrawLine(p, x, 225 - 2, x, 225 + 2); 
            }
            for (x = 225; x > 0; x = x - skala)
            {
                g.DrawLine(p, x, 225 - 2, x, 225 + 2);
            }
            for (y = 225; y < 450; y = y + skala)
            {
                g.DrawLine(p, 225 - 2, y, 225 + 2, y);
            }
            for (y = 225; y > 0; y = y - skala)
            {
                g.DrawLine(p, 225 - 2, y, 225 + 2, y);
            }

            for (x = -225; x <= 225; x++)
            {
                p.Color = Color.Red;
                y = float.Parse(rownanieL[2].ToString()) * x * x + float.Parse(rownanieL[1].ToString()) * x + float.Parse(rownanieL[0].ToString());
                if (x != -225)
                    g.DrawLine(p, 225 + (x * skala), 225 - (y * skala), 225 + (x1 * skala), 225 - (y1 * skala));
                x1 = x;
                y1 = y;

            }

            wykres.Image = bmp;
            wykres.Invalidate();
            
        }

Zmienna skala określa oczywiście skale i można ją zmieniać w zakresie <1; nieskończoność). Jest to dokładniej ilość pikseli przypadających na jedną jednostke na osi. Wielkość układu i wykresu sie nawet zmienia i dla funkcji prostoliniowych w zupełności to wystarczy. Problem pojawia sie właśnie przy paraboli bo przy skali równej np 30 odległość między kolejnymi punktami wynosi 30px. Kiedy następnie te punkty połącze liniami parabola wychodzi kanciasta.

Wykres w skali 30:
user image

W skali 10 wygląda troche lepiej ale też jest "kanciasty":
user image

Jakieś wskazówki? Trzeba by to było jakoś tak zrobić żeby dla każdego kolejnego piksela x obliczał wartość y a nie tylko co ileś pikseli. Tylko jak wtedy skale zastosować?

0

Może g.DrawCurve ? Nie używałem tego wprawdzie, ale raczej o to chodzi.

y = float.Parse(rownanieL[2].ToString()) * x * x + float.Parse(rownanieL[1].ToString()) * x + float.Parse(rownanieL[0].ToString());

Radziłbym te parse'y robić poza pętlą.

I nie tworzyć za każdym razem bitmapy (chyba że tylko raz rysujesz to ok), ale lepiej użyć BufferedGraphics i tam rysować jak się dane zmieniają, a później tylko Render.

0

Może g.DrawCurve ? Nie używałem tego wprawdzie, ale raczej o to chodzi.

Dzięki, działa :)

Radziłbym te parse'y robić poza pętlą.

Ok, znowu masz racje :P

I nie tworzyć za każdym razem bitmapy (chyba że tylko raz rysujesz to ok), ale lepiej użyć BufferedGraphics i tam rysować jak się dane zmieniają, a później tylko Render.

Mógłbyś coś więcej powiedzieć? Może jakiś przykładowy kod? Bo nie za bardzo wiem o co chodzi...

0
Mac123 napisał(a)

I nie tworzyć za każdym razem bitmapy (chyba że tylko raz rysujesz to ok), ale lepiej użyć BufferedGraphics i tam rysować jak się dane zmieniają, a później tylko Render.

Mógłbyś coś więcej powiedzieć? Może jakiś przykładowy kod? Bo nie za bardzo wiem o co chodzi...

Widzisz, jakbyś ten wykres chciał często uaktualniać (np jakieś suwaki, mówie teoretycznie :) ) to tworzenie Bitmap'y jest dość czasochłonne, już lepiej tą bitmapę utworzyć poza funkcją, ale to jeszcze nie jest tak jak się to powinno robić. Do tego jest specjalna klasa - BufferedGraphics, użycie jest banalne :)

Np. w konstruktorze robisz tak:

buffer = BufferedGraphicsManager.Current.Allocate (pictureBox1.CreateGraphics (), pictureBox1.ClientRectangle);

To tzw. podwójne buforowanie.
później gdzieś w kodzie:

Graphics g = buffer.Graphics;
g.Clear (Color.White);
..i rysujesz, a na końcu:
buffer.Render ();

A co lepsze, możesz zrobić sobie np, dwa buffory i w jednym narysować podziałkę (tylko raz, np. zaraz po utworzeniu tego buffora), a później tylko renderować go na główny buffer, w którym narysujesz już tylko wykres funkcji.

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