Graphics mit Antialias verursacht Lücken

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Graphics mit Antialias verursacht Lücken

    Hallo

    Ich habe gerade ein Problem beim Zeichnen mit GDI+.
    Zuerst habe ich ein Projekt erstellt, in dem alles in einem ist.
    Zykloide Formen werden auf der Form gezeichnet.
    SmoothingMode ist auf Antialias gestellt.

    Soweit sogut, alles funktioniert bestens.

    Aber jetzt wollte ich den Teil, bei dem gezeichnet wird auslagern in eine Dll.
    Das funktioniert auch bis zu einem gewissen Punkt problemlos.
    In der Dll wird genau das Selbe gemacht wie in dem anderen Projekt:
    Ein Timer inkrementiert zwei Werte und invalidiert die übergebene Form; In der mit dem Paint Event verknüpften Sub wird das Errechnete gezeichnet (mit Antialias). Ein paar Unterschiede gibt es natürlich: Eine Referenz zur Form wird zum Zeichnen übergeben. Und der Mittelpunkt wird nicht mehr in Variablen zwischengespeichert (ich erhoffte mir eine Geschwindigkeitsverbesserung), sondern direkt per Form.ClientRectangle.Width / 2 (und mit Height) ausgerechnet. Und für X und Y gibt es getrennte Faktoren. Aber in diesem Beispiel haben beide den selben Wert (1).

    Das funktioniert gut, bis ich die Form auf mindestens den halben Bildschirm (1366 x 768) vergrößere. Dann werden immer bei bestimmten Positionen Linien nicht gezeichnet.
    Das passiert nur mit SmoothingMode auf Antialias. Wenn nichts angeben wird tritt dieses Problem nicht auf. Also wird es an den Berechnungen meinerseits nicht liegen.

    Siehe Screenshot: Links Projekt mit Alles in Einem (Antialias ein), Rechts Projekt mit Dll (Antialias ein).


    Dagegen hier: Links Projekt mit Alles in Einem (Antialias ein), Rechts Projekt mit Dll (Antialias aus).


    Wieder ein Bug von MS?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Schalte Antialias einfach aus. Wo ist das Problem?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das ist mir schon klar. Nur wenn derart große Lücken entstehen, nehme ich die Effekte in Kauf oder ich beseitige die Ursache.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    mh, das ist merkwürdig...
    vllt bringt es etwas wenn du doublebuffered auf true schaltest.. ansonsten zeige mal etwas code der zeichnroutine bzw verändere ihn. das ganze lässt sich ja auf mehrere wege realisieren (polygon ausfüllen, region, graphicspath,..). Es ist ja möglich, das wie du schon sagst sich von Seiten Microsofts ein Fehler eingeschlichen hat und du diesen so umgehen kannst..
    DoubleBuffered ist auf True. Bei beiden Projekten. Und Antialias ist hier wirklich unerlässlich. Die Kanten sehen ansonsten wirklich nicht schön aus.

    Hier beim ersten Projekt:

    VB.NET-Quellcode

    1. Dim OffsetX As Double 'wird beim Resizen durch Me.Width / 2 errechnet
    2. Dim OffsetY As Double '... durch Me.Height
    3. Dim SizeFactor As Double = 1
    4. Dim AngleX As Double
    5. Dim AngleY As Double
    6. Dim AngleIncrementX As Double = 0.1
    7. Dim AngleIncrementY As Double = 0.1
    8. Dim FadeOutDevider As Integer = 256
    9. Dim FadeOutAngleSize As Double = 3.14
    10. '.....
    11. Private Sub Calculate() Handles Timer_Increment.Tick
    12. AngleX += AngleIncrementX
    13. AngleY += AngleIncrementY
    14. If AngleX >= Math.PI * 2.0 Then
    15. AngleX -= Math.PI * 2.0
    16. End If
    17. If AngleY >= Math.PI * 2.0 Then
    18. AngleX -= Math.PI * 2.0
    19. End If
    20. Me.Invalidate()
    21. End Sub
    22. Private Function FunctionOf(ByVal Angle As Double, ByVal i As Double, ByVal Offset As Double) As Single
    23. Return CSng(Math.Sin(Angle + i * FadeOutAngleSize) * Offset * SizeFactor + Offset)
    24. End Function
    25. Private Sub MePaint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    26. e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    27. For i As Integer = FadeOutDevider - 1 To 0 Step -1
    28. e.Graphics.DrawLine(New Pen(Color.FromArgb(CByte(i * 255 / FadeOutDevider), 0, 255, 0)), _
    29. FunctionOf(AngleX, i, OffsetX), _
    30. FunctionOf(AngleY, i, OffsetY), _
    31. FunctionOf(AngleX - FadeOutAngleSize, i, OffsetX), _
    32. FunctionOf(AngleY - FadeOutAngleSize, i, OffsetY))
    33. Next
    34. End Sub


    Und im Dll Projekt:

    VB.NET-Quellcode

    1. Dim Container As Form 'Wird im Konstruktor vom ausführenden Projekt übergeben
    2. Dim SizeFactorX As Double = 1
    3. Dim SizeFactorY As Double = 1
    4. Dim AngleX As Double
    5. Dim AngleY As Double
    6. Dim AngleIncrementX As Double = 0.1
    7. Dim AngleIncrementY As Double = 0.1
    8. Dim FadeOutDevider As Integer = 256
    9. Dim FadeOutAngleSize As Double = 3.14
    10. Dim Smooth As Boolean = True
    11. Private Sub NewTick() Handles Timer_NewTick.Elapsed
    12. AngleX += AngleIncrementX
    13. AngleY += AngleIncrementY
    14. If AngleX >= Math.PI * 2.0 Then
    15. AngleX -= Math.PI * 2.0
    16. End If
    17. If AngleY >= Math.PI * 2.0 Then
    18. AngleX -= Math.PI * 2.0
    19. End If
    20. Container.Invalidate()
    21. End Sub
    22. Private Function FunctionOf(ByVal Angle As Double, ByVal i As Double, ByVal Offset As Double, ByVal SizeFactor As Double) As Single
    23. Return CSng(Math.Sin(Angle + i * FadeOutAngleSize) * Offset * SizeFactor + Offset)
    24. End Function
    25. Private Sub PaintContainer(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) 'Im Konstruktor wird per AddHandler der Event verknüpft
    26. If Smooth Then
    27. e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
    28. End If
    29. For i As Integer = FadeOutDevider - 1 To 0 Step -1
    30. e.Graphics.DrawLine(New System.Drawing.Pen(System.Drawing.Color.FromArgb(CByte(i * 255 / FadeOutDevider), 0, 255, 0)), _
    31. FunctionOf(AngleX, i, Container.ClientRectangle.Width / 2, SizeFactorX), _
    32. FunctionOf(AngleY, i, Container.ClientRectangle.Height / 2, SizeFactorY), _
    33. FunctionOf(AngleX - FadeOutAngleSize, i, Container.ClientRectangle.Width / 2, SizeFactorX), _
    34. FunctionOf(AngleY - FadeOutAngleSize, i, Container.ClientRectangle.Height / 2, SizeFactorY))
    35. Next
    36. End Sub


    Das sind die signifikanten Codeteile.


    Ich habe allerdings sowiso vor in der TimerTick Sub ein Array von Punkten errechnen zu lassen und dieses einfach in der Paint Sub zu zeichnen.
    Vielleicht hilft das.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    So wie ich das sehe zeichnest du zig Linien mit verschiedenen Farben um diesen farbübergang zu machen. Ich denke es liegt an diesem extrem unperformanten Vorgang. Zeichne doch besser 2 polyfone mit blend-Effekt. Sie dir gdi mal genauer an, auch Rotation etc
    Dann wären aber andere Dinge nicht mehr möglich. Siehe:


    Dass es nicht sonderlich performant ist weiß ich. Aber ich stelle später auch um auf DrawLines(pen As System.Drawing.Pen, points() As System.Drawing.Point) und lasse die Punkte in der Timer Tick Sub ausrechnen.

    Aber danke für den Hinweis dass man Farbverläufe dieser Art auch anders hinbekommt.
    PS: Meintest Du Polygone?



    Edit:
    Ach mist. Das geht ja gar nicht. Dann werden die Linien alle mit der selben Farbe gezeichnet. Aber vielleicht bringt die Verlagerung der Berechnung etwas.



    Edit2:
    Ich habe jetzt etwas herausgefunden. Es scheint tatsächlich mit der Auslastung zutun haben. Wenn man den Intervall größer macht tritt das Problem nur noch auf, wenn die Fächer schmal sind. Und wenn man den Intervall verkleinert tritt das Problem ganz extrem auf.

    Ich habe das Berechnen der Punkte jetzt in die Timer Tick Sub verlegt. Das hat einiges gebracht. Das Problem tritt nur noch bei sehr engen Fächern auf.

    Das Problem tritt aber weiterhin nicht beim Projekt auf wo alles in einem ist. Belastet das Arbeiten mit der Dll die CPU so sehr?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Niko Ortner“ ()

    Es hat sich was verändert, aber es ist immer noch nicht weg.
    Bilder
    • Unbenannt2.png

      405,47 kB, 1.366×768, 158 mal angesehen
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils