1. Liebe Forumsgemeinde,

    aufgrund der Bestimmungen, die sich aus der DSGVO ergeben, müssten umfangreiche Anpassungen am Forum vorgenommen werden, die sich für uns nicht wirtschaftlich abbilden lassen. Daher haben wir uns entschlossen, das Forum in seiner aktuellen Form zu archivieren und online bereit zu stellen, jedoch keine Neuanmeldungen oder neuen Kommentare mehr zuzulassen. So ist sichergestellt, dass das gesammelte Wissen nicht verloren geht, und wir die Seite dennoch DSGVO-konform zur Verfügung stellen können.
    Dies wird in den nächsten Tagen umgesetzt.

    Ich danke allen, die sich in den letzten Jahren für Hilfesuchende und auch für das Forum selbst engagiert haben. Ich bin weiterhin für euch erreichbar unter tti(bei)pcwelt.de.
    Dismiss Notice

C# GraphicsPath rotation

Discussion in 'Programmieren' started by Aequitas, Mar 25, 2010.

Thread Status:
Not open for further replies.
  1. Aequitas

    Aequitas Kbyte

    Hallo ich habe ein kleines Problem mit C#.
    Ich hab für meine matura(abitur) für informatik ein Programm geschrieben in dem ich mit c# das Planetensystem simuliere natürlich stark vereinfacht!
    für die Planeten wurde für jeden ein graphicspath erstellt der dann mithilfe eines timers und matrix um einen mittelpunkt(sonne) rotiert.
    das problem ist jetzt das es zwar halbwegs funktioniert jedoch flackert das ganze ziemlich stark also ist nicht besonders schön anzusehen. und hin und wieder ist dass ganze bild weg, die planeten kommen dann natürlich wieder da sie ja vom timer immer wieder neu gezeichnet werden aber die sonne und die sterne sind dann weg :(


    hier ein kleines beispiel wie ich die rotation gemacht habe:


    namespace drehenversuch
    {
    public partial class Form1 : Form
    {
    private GraphicsPath merkur = new GraphicsPath();

    private PointF m_mittel;
    private Graphics m_myGraph;



    public Form1()
    {
    InitializeComponent();
    merkur.AddEllipse(500, 325, 55, 55);
    m_myGraph = CreateGraphics();
    }



    private void timer1_Tick(object sender, EventArgs e)
    {

    m_mittel = new PointF(500, 450);
    Matrix m = new Matrix();

    m_myGraph.FillPath(new SolidBrush(Color.Gray), merkur);
    m.RotateAt(5, m_mittel);
    merkur.Transform(m);
    m = new Matrix();

    m_myGraph.FillPath(new SolidBrush(Color.DarkBlue), merkur);


    }
    }
    }

    kann man das irgentwie machen dass das ganze etwas "stabieler" läuft???
    wäre ziemlich cool.
     
  2. Fettbemme

    Fettbemme Halbes Megabyte

    Das was Du da machen möchtest, ist eigentlich eher eine Aufgabe für Direct 3D oder OpenGL. GDI+, das was Du da in C# verwendest ist für 3D Transformationen nur wenig geeignet. GDI+ zeichnet sich auch noch daduch aus, dass es recht langsam ist.
    Als Abhilfe wäre es vielleicht möglich in einem Speicherkontext eine neue Planetenpostion zu zeichen, und dann in den Kontext der Grafikkarte kopieren (BitBlt).
     
  3. Aequitas

    Aequitas Kbyte

    Naja dass problem ist eben das ich nu c# behersche. Dieses programm hab ich als Spezialgebiet für meine Matura geschrieben, und mich stört es dass es so ruckelt. Ein Freund von mir meinte das man das mit Threading beheben könnte aber ich hab null ahnung wie dass geht...
     
  4. Fettbemme

    Fettbemme Halbes Megabyte

    Prinzipiell kannst Du DirectX und OpenGL auch unter C# verwenden, ggf. über Bibliotheken. (http://csgl.sourceforge.net/)

    Das Problem ist, dass man das ganze nicht gleich gelernt hat.

    Nun Dein Grundproblem ist letztlich, Du möchtest bewegte Objekte darstellen. Dafür hat MS unter Windows DirectX eingeführt, weil die GDI (und GDI+ auch) zu langsam ist um bewegte Dinge flüssig darzustellen. OpenGL umgeht bei modernen Grafikkarten benfalls die GDI, da die Grafiktreiber in aller Regel OpenGL oder teile davon unterstützen. Meine Erfahrung ist halt, dass GDI für "Animationen" zu langsam ist.

    Um Flackern zu reduzieren ist der Ansatz vielleicht hilfreich, das neue Bild in einem Speicherkontext zu zeichenen (Bei C++ eine MemoryDC) und nachdem das Bild im Hintergrund berechnet und gezeichnet wurde einfach über BitBlt in den Device Context der Grafikkarte kopieren. Sowas sollte auch unter C# möglich sein, habe es aber da noch nicht gemacht, daher kann ich nicht mehr Details liefern. Flackern kann man über diese Art zumindest beheben, das man das löschen des bildschirmes nicht sieht. Ruckeln ist damit aber nicht behebbar.

    Inwieweit Threading das Problem löst weis ich nicht. Was verwendest Du denn für einen PC (CPU, RAM, Grafik). Ich denke mal wenn es Flackert, dann sieht man einfach das löschen des Zeichenbereiches.

    Hier sind vielleicht zwei Links die in die Richtung gehen was ich meine:
    http://www.codeguru.com/csharp/csharp/cs_graphics/drawing/article.php/c6137
    http://www.codeproject.com/KB/GDI-plus/flickerFreeDrawing.aspx
     
    Last edited: Apr 14, 2010
  5. luker

    luker Byte

    Hallo Aequitas,

    es sieht so aus, als habest Du zwei Probleme:
    1. Objekte verschwinden
    2. Flackern

    1. Lässt sich lösen, indem Du _alle_ Zeichenoperationen in die Methode OnPaint() packst. Sie wird bei Bedarf aufgerufen und zeichnet dann alles neu.
    Getrennt davon sollte die Berechnung ablaufen. In Timer1_Tick() ist sie gut aufgehoben. Nur sollte sich Timer1_Tick() auf die Berechnung beschränken, alle Ergebnisse der Berechnungen in Variablen speichern und das Zeichnen OnPaint() überlassen.

    2. Wird, wie schon in Fettbemmes Links erwähnt, durch double buffering ausgemerzt. Du musst deswegen nicht gleich OpenGL lernen, auch wenn das an sich keine schlechte Idee ist.

    Das folgende Control ist von Panel abgeleitet, arbeitet mit double buffering und trennt Berechnung von Darstellung
    Code:
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace Test_DoubleBuffer
    {
        public class DrawingPanel:Panel
        {
            #region Declarations
    
            private List<CelestialBody> orbs = new List<CelesialBody>();
    
            #endregion
    
    
            #region Init
    
            public DrawingPanel()
            {
                // Make this panel double-buffered
                this.SetStyle(
                    System.Windows.Forms.ControlStyles.UserPaint |
                    System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
                    System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, true
                );
            }
    
            #endregion
    
    
            #region Processing
    
            private void MyTimer_Tick()
            {
                // Go through a list of planets, moons, stars, whatever
                //   and process positions, rotations and so on
    
                // After all processing is done, tell the OS to redraw this panel
                //   The OnPaint() method will get called soon.
                this.Invalidate();
            }
    
            #endregion
    
    
            #region Drawing
    
            protected override void OnPaint(PaintEventArgs e)
            {
                // I'm not sure if base.OnPaint() is necessary in case you
                //   draw the background yourself
                base.OnPaint(e);
    
                // Draw your background
                DrawBackground();
    
                // Draw your objects
                DrawObjects();
            }
    
    
            private void DrawBackground()
            {
                // Draw Whatever is in the Background
            }
    
    
            private void DrawObjects()
            {
                // Go through a list of planets, moons, stars, whatever
                //   and paint everything in its current location
            }
    
            #endregion
        }
    
    
        public class CelestialBody
        {
            #region Declarations
    
            private PointF location = new PointF(0, 0);
            private float size = 4;
            private Color color = Color.Yellow;
    
            #endregion
        }
    }
    
    Diese Klasse kannst Du wie ein "normales" Panel auf eine Form ziehen, unter "Eigenschaften" -> "Dock" auf "Fill" setzen und den Code für Berechnung und Zeichnen an den entsprechenden stellen einfügen.

    Viel Glück.
     
Thread Status:
Not open for further replies.

Share This Page