Hopalong - Fraktal

    • VB.NET

    Es gibt 84 Antworten in diesem Thema. Der letzte Beitrag () ist von zn-gong.

      Ich habe mal versucht, es möglichst performant hinzubekommen. Der Code generiert nun eine beliebige Anzahl an Frames, welche dann später (oder auch direkt) zu einer Animation weiterverarbeitet werden können. Der Code, der das Fraktal generiert, sieht folgendermaßen aus:

      VB.NET-Quellcode

      1. Public Class HopalongGenerator
      2. Private bmp As Bitmap
      3. Public Property Image As Bitmap
      4. Get
      5. Return bmp
      6. End Get
      7. Set(value As Bitmap)
      8. bmp = value
      9. End Set
      10. End Property
      11. ''' <summary>
      12. ''' Gibt an, dass sich das aktuelle Abbild des Fraktals geändert hat
      13. ''' </summary>
      14. ''' <param name="img">Das aktuelle Abbild</param>
      15. ''' <param name="iterations">Die Anzahl der Iterationen, die auf dem Bild abgebildet sind</param>
      16. Public Event ImageChanged(img As Bitmap, iterations As Long)
      17. ''' <summary>
      18. ''' Generiert ein Hopalong-Fraktal
      19. ''' </summary>
      20. ''' <param name="iterations">Die Anzahl der zu generierenden Iterationen</param>
      21. ''' <param name="zoom">Die Zoomstufe</param>
      22. ''' <param name="colorjump">Der Farbsprung</param>
      23. ''' <param name="size">Die Größe des zu generierenden Abbildes</param>
      24. ''' <param name="a">A</param>
      25. ''' <param name="b">B</param>
      26. ''' <param name="c">C</param>
      27. Public Sub GenerateHopalong(iterations As Long, zoom As Double, colorJump As Integer, colorFormula As Integer, size As Size, a As Double, b As Double, c As Double, frames As Integer)
      28. 'Überprüfen, ob die übergebene Anzahl der Iterationen überhaupt möglich ist
      29. If Not iterations > 0 Then Throw New ArgumentOutOfRangeException("The number of Iterations has to be higher than 0")
      30. 'Hier wird nachher reingerendert
      31. Dim TargetBitmap As New Bitmap(size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
      32. 'Hintergrund --> Schwarz
      33. Using g As Graphics = Graphics.FromImage(TargetBitmap)
      34. g.Clear(Color.Black)
      35. End Using
      36. 'Die Bildproperty aktualisieren und das Event auslösen
      37. bmp = DirectCast(TargetBitmap.Clone(), Bitmap)
      38. RaiseEvent ImageChanged(bmp, 0)
      39. 'Vorbereitung
      40. Dim ColorCount As Integer = 0
      41. Dim DistH As Integer = size.Width \ 2
      42. Dim DistV As Integer = size.Height \ 2
      43. 'Alle X Iterationen das Bild aktualisieren und übergeben
      44. Dim IterationsPerFrame As Double = iterations / frames
      45. 'Hier werden alle für diesen Frame zu rendernden Punkte gespeichert.
      46. Dim FrameIterationCount As Double = 0
      47. Dim DrawQuery As New Queue(Of Tuple(Of Point, Color))
      48. Dim X As Double = 1
      49. Dim Y As Double = 1
      50. For Iteration As Long = 1 To iterations
      51. 'Farbe festlegen
      52. ColorCount = CInt(Math.Max(1, (ColorCount Mod 256)))
      53. Dim Col As Color = GetColorFormula(colorFormula, ColorCount)
      54. Dim ptX As Integer = CInt(X * zoom + DistH)
      55. Dim ptY As Integer = CInt(Y * zoom + DistV)
      56. 'Punkt abspeichern
      57. DrawQuery.Enqueue(Tuple.Create(New Point(ptX, ptY), Col))
      58. 'Neue Koordinaten berechnen
      59. Dim xx As Double = Y - Math.Sign(X) * Math.Sqrt(Math.Abs(b * X - c))
      60. Dim yy As Double = a - X
      61. If Math.Abs(X - xx) < colorJump Then ColorCount += 1
      62. 'Wenn alle Iterationen für den aktuellen Frame fertig sind, den Frame mit LockBits zeichnen
      63. If FrameIterationCount >= IterationsPerFrame Then
      64. FrameIterationCount = FrameIterationCount - IterationsPerFrame
      65. Dim LockData As Imaging.BitmapData = TargetBitmap.LockBits(New Rectangle(0, 0, TargetBitmap.Width, TargetBitmap.Height), Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
      66. Dim Bytes As Integer = Math.Abs(LockData.Stride) * TargetBitmap.Height
      67. Dim ArgbValues(Math.Abs(LockData.Stride) * TargetBitmap.Height - 1) As Byte
      68. System.Runtime.InteropServices.Marshal.Copy(LockData.Scan0, ArgbValues, 0, Bytes)
      69. 'Alle Punkte zeichnen
      70. For Each t In DrawQuery
      71. Dim Index As Integer = (t.Item1.Y * TargetBitmap.Width * 3) + (t.Item1.X * 3)
      72. 'Nur drei Werte da nur 24 Bit (RGB)
      73. If Not (Index + 2 > ArgbValues.GetLength(0) - 1 OrElse Index < 0) Then
      74. ArgbValues(Index) = t.Item2.R
      75. ArgbValues(Index + 1) = t.Item2.G
      76. ArgbValues(Index + 2) = t.Item2.B
      77. End If
      78. Next
      79. System.Runtime.InteropServices.Marshal.Copy(ArgbValues, 0, LockData.Scan0, Bytes)
      80. TargetBitmap.UnlockBits(LockData)
      81. 'Das aktuelle Bild zurückgeben
      82. bmp = DirectCast(TargetBitmap.Clone(), Bitmap)
      83. RaiseEvent ImageChanged(bmp, Iteration)
      84. End If
      85. X = xx
      86. Y = yy
      87. FrameIterationCount += 1
      88. Next
      89. 'Am Ende das Bild nochmal zurückgeben
      90. bmp = DirectCast(TargetBitmap.Clone(), Bitmap)
      91. RaiseEvent ImageChanged(bmp, iterations)
      92. End Sub
      93. Private Function GetColorFormula(i As Integer, cc As Integer) As Color
      94. Select Case i
      95. Case 0
      96. Return Color.FromArgb(255 - cc, cc, CInt(127 + cc / 2))
      97. Case 1
      98. Return Color.FromArgb(255 - cc, CInt(127 + cc / 2), cc)
      99. Case 2
      100. Return Color.FromArgb(cc, CInt(127 + cc / 2), 255 - cc)
      101. Case 3
      102. Return Color.FromArgb(cc, 255 - cc, CInt(127 + cc / 2))
      103. Case 4
      104. Return Color.FromArgb(CInt(127 + cc / 2), cc, 255 - cc)
      105. Case 5
      106. Return Color.FromArgb(CInt(127 + cc / 2), 255 - cc, cc)
      107. Case Else
      108. Return Color.FromArgb(255 - cc, cc, CInt(127 + cc / 2))
      109. End Select
      110. End Function
      111. End Class

      Es funktioniert auch alles, jedoch denke ich, dass ich irgendwo in der Berechnung des aktuellen Punktes einen Fehler gemacht habe, schau dir einfach mal den Teil ab Zeile 65 an, vielleicht findest du ja den Fehler ;).
      Für den Code habe ich auch noch eine Form mit etwas Code im Hintergrund auf die Schnelle hingeklatscht, nicht sehr sauber, funktioniert aber mit Multithreading.
      Im Anhang ist noch das Projekt, damit du dir auch mal ein Bild davon machen kannst.
      Dateien

      ThePlexian schrieb:

      Was zählst du denn noch alles zu Grundlagen wenn ich mal fragen darf? ^^
      ich meinte nix konkretes - das kommt ganz drauf an (es ging ja darum, ob ein Tutorial zur Engine prinzipiell möglich sei, oder ob der User durch herum-üben damit von selbst drauf kommen müsse).
      Wenn einer seine Engine erklärt, und man stößt auf eine Zeile, die der Leser nicht versteht, dann muß da nach-erklärt werden.
      Und es handelt sich dabei nicht um Erklärungen der Engine, sondern was anneres.

      Also Grundlagen sind alles, was zusätzlich erklärt werden muss, damit die eigentliche Erklärung der Engine ühaupt verstanden werden kann.
      Okay vielen Dank @nafets3646, aber ich habe noch ein paar Fragen:

      1. Zeile 62 und 74 sind doch iwie doppelt oder ?
      2. In Zeile 109 addierst du nur 1 dazu, also ist doch in Zeile 77 ">=" durch "=" ersetzbar, und in Zeile 78 kann man direkt FrameIterationCount = 0 schreiben, oder ?
      3. frames sind die Anzahl der Bilder, die man gesamt braucht, wenn man bei x Iterationen eine Framerate von f haben will ?
      4. Scheinbar ist mir das immer noch nicht ganz klar, wo trennst du da Graphik von Logik bitte ?

      Aber dankeschön soweit :)


      @ErfinderDesRades:
      Achso, ja macht Sinn ^^
      »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
      @ThePlexian
      Oh, ich hatte wohl vergessen zu speichern, bevor ich das Programm geschlossen hatte. Der Code scheint noch aus einer der Vorversionen zu kommen, ich schau mal, ob ich das noch hinbekomme ;).
      Interesantes Thema,ich bekunde dann auch mal Interesse für einen Background eines MDI Fensters^^