Przyspieszenie rysowania grafiki

0

Piszę aplikację, w której jest możliwość rysowania grafów. Niby działa, jednak gdy jest dużo obiektów, tzn. wierzchołków i krawędzi to całość topornie się przerysowuje (np. podczas ich przesuwania). Jak temu zaradzić?
PS. doublebuffer nic nie pomaga.

0

najpierw napisz w czym rysujesz: urządzeniem graphics czy w Open GL? Pokaż też część kodu.

0

graphics + obiekty vb.powerpacks

  private void RysujKrawedz(int krawedz, TextBox textB)
        {
            // Pobiera krawędź do rysowania oraz punkty łączące
            Krawedz p = krawedzie[krawedz];
            Wierzcholek from = wierzcholki[p.from];
            Wierzcholek to = wierzcholki[p.to];

            Point pFrom = new Point(from.owal.Location.X + size / 2, from.owal.Location.Y + size / 2);
            Point pTo = new Point(to.owal.Location.X + size / 2, to.owal.Location.Y + size / 2);
           

            Graphics g = panel1.CreateGraphics();
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            
            pen.StartCap =  LineCap.Round;
            pen.EndCap = LineCap.ArrowAnchor;
            g.DrawLine(pen, PrzesunieciePunktu.nowyFrom(pFrom, pTo, size + 6),
                            PrzesunieciePunktu.nowyTo(pFrom, pTo, size + 6));
            textB.Name = krawedz.ToString();
            textB.Size = new System.Drawing.Size(30, 20);
            textB.Location = new System.Drawing.Point(((pFrom.X + pTo.X) / 2) - textB.Size.Width / 2,
                ((pFrom.Y + pTo.Y) / 2) - textB.Size.Height / 2);
            textB.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            textB.TextAlign = HorizontalAlignment.Center;
            textB.Leave += new EventHandler(textBoxWartosc_Leave);
            textB.Parent = panel1;
            g.Dispose();
        }
private void dodajWierzcholek(int X, int Y, int S1, int S2)
        {
            OvalShape owal = new OvalShape();
            wierzcholki.Add(new Wierzcholek(new Point(X, Y), numV, owal));
            numV += 1;
            wierzcholki[wierzcholki.Count - 1].owal.Location = new Point(X - size/2, Y- size/2);
            wierzcholki[wierzcholki.Count - 1].owal.Size = new Size(S1, S2);
            wierzcholki[wierzcholki.Count - 1].owal.Parent = kontener;
            wierzcholki[wierzcholki.Count - 1].owal.BorderColor = Color.Black;
            wierzcholki[wierzcholki.Count - 1].owal.BackStyle = BackStyle.Transparent;
            //wierzcholki[wierzcholki.Count - 1].owal.BackColor = Color.DodgerBlue;
            wierzcholki[wierzcholki.Count - 1].owal.BorderWidth = 1;
            int wieName = numV - 1;
            wierzcholki[wierzcholki.Count - 1].owal.Name = wieName.ToString();
            wierzcholki[wierzcholki.Count - 1].owal.Cursor = System.Windows.Forms.Cursors.Hand;
            // zdarzenia myszy
            wierzcholki[wierzcholki.Count - 1].owal.MouseDown += new MouseEventHandler(chwyt);
            wierzcholki[wierzcholki.Count - 1].owal.MouseEnter += new EventHandler(wejscie);
            wierzcholki[wierzcholki.Count - 1].owal.MouseLeave += new EventHandler(wyjscie);
            wierzcholki[wierzcholki.Count - 1].owal.MouseClick += new MouseEventHandler(owal_MouseClick);
            // menu kontekstowe
            wierzcholki[wierzcholki.Count - 1].owal.ContextMenu = new ContextMenu();
            wierzcholki[wierzcholki.Count - 1].owal.ContextMenu.MenuItems.Add("Usuń", new System.EventHandler(this.usunMenuItem_Click));
            wierzcholki[wierzcholki.Count - 1].owal.ContextMenu.MenuItems.Add("Anuluj", new System.EventHandler(this.anulujMenuItem_Click));
        }   

oraz zdarzenia odpowiedzialne za przesuwanie wierzchołków

private void chwyt(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && radioButtonW.Checked)
            {
                ow = (OvalShape)sender;
                Xpos = MousePosition.X;
                Ypos = MousePosition.Y;
                ow.MouseMove += new MouseEventHandler(przesuwam);
                ow.MouseUp += new MouseEventHandler(puscilem);
            }
        }         
        private void przesuwam(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && radioButtonW.Checked)
            {
                OvalShape ow = (OvalShape)sender;
                zmianaX = MousePosition.X - Xpos;
                zmianaY = MousePosition.Y - Ypos;

                foreach (int w in listaKr)
                {
                    RysujKrawedz(w, krawedzie[w].textB);
                }

                ow.Location = new Point(ow.Location.X + zmianaX, ow.Location.Y + zmianaY);
                Xpos = MousePosition.X;
                Ypos = MousePosition.Y;
                textBox1.Text = "Name: " + ow.Name + ", Pozycja: " + ow.Location + ", ilość krawędzi: " + listaKr.Count.ToString();
                
            }
           

        }
        private void puscilem(object sender, MouseEventArgs e)
        {
            OvalShape ow = (OvalShape)sender;
            if (e.Button == MouseButtons.Left && radioButtonW.Checked)
            ow.MouseMove -= new MouseEventHandler(przesuwam);
        } 
0

Opisany przez Ciebie problem raczej jest spowodowany tym, że rysujesz cały graf prawdopodobnie zbyt często. Samo rysowanie powinieneś wykonywać tylko i wyłącznie w momencie zmiany grafu (jak dodanie/usunięcia wierzchołka czy krawędzi) zapisaniu Bitmapy do zmiennej i potem w momencie odrysowywania brać swój obraz grafu. Jeżeli rysujesz graf za każdym razem kiedy przemieszczasz okno/zmieniasz jego rozmiar to jest to bez sensu - jeżeli chcesz aby graf dopasowywał się wielkością do okna to zawsze możesz narysować bitmapę w skali 1:1 a potem ją zmniejszyć - możesz wtedy skorzystać z LockBit'a (http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx) oraz BitmapData (http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx) oraz jakiegoś algorytmu w celu zmniejszenia już samej zawartości bitmapy.

Poza tym widzę, że do każdego z obiektów jakim jest wierzchołek przypisujesz olbrzymią ilość klas czy zdarzeń. Spróbuj inaczej to rozwiązać. - Np. możesz trzymać wyłącznie współrzędne wierzchołków. Na obiekcie na którym rysujesz ów graf zrób swoje zdarzenia (np. ruch myszki) i sprawdzaj czy znajdujesz się na którymś z punktów (ew. obok niego) i tak samo zrób sprawdzanie po kliknięciu prawym przyciskiem myszy czy jesteś w jakimś wierzchołku i jeżeli jesteś to faktycznie wyświetl menu kontekstowe.

Ja bym jakoś tak próbował, acz nie daje gwarancji, że to na pewno zdałoby egzamin.

0

Dzięki za pomoc, sprawdzę to z bitmapami.
Wytłumaczę tylko jak działa to "przesuwanie obiektów":
Po najechaniu myszka na wierzchołek wywoływane jest zdarzenie

  private void wejscie(object sender, EventArgs e)
        {
            OvalShape ow = (OvalShape)sender;
            ow.BorderColor = Color.Red;

            int numer = Int32.Parse(ow.Name);
            foreach (Krawedz kr in krawedzie)
            {
                if (kr.from == numer || kr.to == numer)
                    listaKr.Add(Int32.Parse(kr.textB.Name));
            }

        }

tworzy listę krawędzi powiązanych z wierzchołkiem.
następnie samo przesuniecie wierzchołka powoduje jedynie zmianę położenia kształtu "owal" reprezentującego wierzchołek

  ow.Location = new Point(ow.Location.X + zmianaX, ow.Location.Y + zmianaY);

oraz przerysowuje krawędzie na podstawie wcześniej wypełnionej listy foreach (int w in listaKr)
{
RysujKrawedz(w, krawedzie[w].textB);
}


wyjście kursora z wierzchołka czyści listę
```csharp
 private void wyjscie(object sender, EventArgs e)
        {
            OvalShape ow = (OvalShape)sender;
            ow.BorderColor = Color.Black;
            listaKr.RemoveAll(delegate(int v)
            {
                return true;
            });
        }

Pytanie:
Czy po wprowadzeniu wcześniej proponowanych zmian, nadal będzie możliwość obsługi tych zdarzeń?

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