Skip to content

Instantly share code, notes, and snippets.

@YC

YC/Attractors.vb Secret

Last active July 19, 2018 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YC/8484eb73b3b66959308d to your computer and use it in GitHub Desktop.
Save YC/8484eb73b3b66959308d to your computer and use it in GitHub Desktop.
Innumerable - Peter de Jong Attractor & Animation
' "de Jong Attractor" by Thor Frølich, licensed under Creative Commons Attribution-Share Alike 3.0 and GNU GPL license.
' Work: http://openprocessing.org/visuals/?visualID=2097
' License: http://creativecommons.org/licenses/by-sa/3.0/ http://creativecommons.org/licenses/GPL/2.0/
' deJong Attractor - Modified by YC and mrrhys
' Changes: Conversion of Code into VB.NET, Calculate/Render Frames without Incremental Updates, Detection of Blanks
' ImageMagick is used for Conversion of Images: https://magick.codeplex.com - Licensed under Apache License 2.0 (Apache)
Option Strict On
Option Explicit On
Option Infer On
Imports System
Public Class Attractor
Public Property ThreadNumber As Integer
Public Property Time As Double ' Elapsed Time
Public Property FNumber As Integer ' Frame Number
' Width and Height of Frame
Dim Width As Integer = 3840
Dim Height As Integer = 2160
Dim Density(Width)() As Double
Dim PreviousX(Width)() As Double
Sub AssignThread(number As Integer)
ThreadNumber = number ' Assign Thread Number for BlankFrames and WorkCaller
End Sub
Sub New()
ThreadNumber = 0 : Time = 0 : FNumber = 0
For i = 0 To Width ' Init Array
Density(i) = New Double(Height) {}
PreviousX(i) = New Double(Height) {}
Next
End Sub
Dim sw As New System.Diagnostics.Stopwatch
Dim HeightMultiplier As Double = (Height / 4 - 50) ' Produce Square Image
Dim XOffset As Integer = (Width - Height) \ 2 ' Center Horizontally
Sub ClearArray() ' Empty Array
For i = 0 To Width
For j = 0 To Height
Density(i)(j) = 0
PreviousX(i)(j) = 0
Next
Next
End Sub
Sub Dejong(variableA As Double, variableB As Double, variableC As Double, variableD As Double, iterations As Integer, fileNumber As Integer)
ClearArray()
Console.WriteLine(AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Thread & ThreadNumber)
RaiseEvent RaiseLogEntry(Me, New LogEntryEventArgs("Thread Started", AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Thread & ThreadNumber))
sw.Reset() : sw.Start()
FNumber = fileNumber ' Set Frame Number
Dim Rnd As New Random
Dim x, y As Double ' x/y coord
Dim XCo, YCo As Integer ' Rounded Coordinates
Dim Nx, Ny As Double ' New x, New y
For i = 0 To iterations
' de Jong Attractor
Nx = Math.Sin(variableA * y) - Math.Cos(variableB * x)
Ny = Math.Sin(variableC * x) - Math.Cos(variableD * y)
' Smoothie and Map Coordinates
XCo = CInt(HeightMultiplier * (Nx + 2) + 100 + CLng((Rnd.NextDouble * 2) - 1) \ 1000)
YCo = CInt(HeightMultiplier * (Ny + 2) + 100 + CLng((Rnd.NextDouble * 2) - 1) \ 1000)
Density(XCo)(YCo) += 1
PreviousX(XCo)(YCo) = x
' Update Current x/y Coordinates
x = Nx
y = Ny
Next
Dim MaxDense As Double = 0 ' Max Logarithmic Density
Dim AverageDensity As Double = 0 ' Density Average (For detecting Empty/Dark Frames)
Dim ct As Integer = 0 ' Pixels
For i = 0 To Width
For j = 0 To Height
If Density(i)(j) > 0 Then
ct += 1 ' Add a pixel
AverageDensity += Density(i)(j)
Density(i)(j) = Math.Log((Density(i)(j))) ' Take Log and Store Value
If Density(i)(j) > MaxDense Then MaxDense = Density(i)(j) ' Set Maxdense as Value
End If
Next
Next
If ct < 5000 Then ' Not enough pixels
RaiseEvent BlankAttractor(Me, New BlankAttractorEventArgs(fileNumber, ThreadNumber, 1, New AttractorFrame(variableA, variableB, variableC, variableD)))
Exit Sub
End If
If (AverageDensity / ct) > 38 Then ' Too dense
RaiseEvent BlankAttractor(Me, New BlankAttractorEventArgs(fileNumber, ThreadNumber, 2, New AttractorFrame(variableA, variableB, variableC, variableD)))
Exit Sub
End If
Console.WriteLine(AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Density & AverageDensity / ct)
Console.WriteLine(AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.LogMax & MaxDense)
RaiseEvent RaiseLogEntry(Me, New LogEntryEventArgs("Density", AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Density & AverageDensity / ct & AttractorResources.AttractorStrings.LogMax & MaxDense & " Number of Pixels " & ct))
Dim BrightTotal As Double
Using bmp As New Drawing.Bitmap(Width, Height) ' Bitmap
For i = 0 To Width - 1 ' Loop through Array
For j = 0 To Height - 1
If Density(i)(j) > 0 Then
Dim Hue = 47.5 * (PreviousX(i)(j) + 2) + 180
Dim Sat = (-1 * Density(i)(j)) / MaxDense + 1
Dim Bright = Density(i)(j) / MaxDense
Dim NewColor = New HSBColour(Hue, Sat, Bright) ' Convert Colour
bmp.SetPixel(i + XOffset, j, NewColor.HSBToRGB) ' Set Pixel Location and Colour
BrightTotal += Bright ' Total Brightness of Image
End If
Next
Next
If (BrightTotal / ct) < 0.075 Then ' Divide by Pixel -> Image is too dark because pixels have roughly the same density
RaiseEvent BlankAttractor(Me, New BlankAttractorEventArgs(fileNumber, ThreadNumber, 3, New AttractorFrame(variableA, variableB, variableC, variableD)))
Exit Sub
End If
Try
Using image As New ImageMagick.MagickImage(bmp) ' Use bmp to convert to PNG (To save space)
image.Alpha(ImageMagick.AlphaOption.Off) ' Turn off Transparency
image.AntiAlias = True
Dim NumberCulture As System.Globalization.NumberFormatInfo = System.Globalization.CultureInfo.GetCultureInfo("en-AU").NumberFormat
image.Write(fileNumber.ToString("000000", NumberCulture) & "_" & variableA & "_" & variableB & "_" & variableC & "_" & variableD & ".png")
End Using
Catch ex As Exception
Throw
End Try
End Using
Time = sw.ElapsedMilliseconds : sw.Stop()
Console.WriteLine(AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Time & sw.ElapsedMilliseconds)
RaiseEvent RaiseLogEntry(Me, New LogEntryEventArgs("Attractor", AttractorResources.AttractorStrings.Frame & fileNumber & " a=" & variableA & ",b=" & variableB & ",c=" & variableC & ",d=" & variableD))
RaiseEvent RaiseLogEntry(Me, New LogEntryEventArgs("Attractor Finished", AttractorResources.AttractorStrings.Frame & fileNumber & AttractorResources.AttractorStrings.Time & sw.ElapsedMilliseconds))
RaiseEvent AttractorFinished(Me, New AttractorFinishedEventArgs(ThreadNumber)) ' Finished Event -> Reallocate Work
RaiseEvent Success(Me, EventArgs.Empty)
Exit Sub
End Sub
Event BlankAttractor As EventHandler(Of BlankAttractorEventArgs)
Event AttractorFinished As EventHandler(Of AttractorFinishedEventArgs)
Event RaiseLogEntry As EventHandler(Of LogEntryEventArgs)
Event Success As EventHandler
End Class
Public Class AttractorFrame ' For storing Frames
Public Property A As Double
Public Property B As Double
Public Property C As Double
Public Property D As Double
Sub New(aValue As Double, bValue As Double, cValue As Double, dValue As Double)
A = aValue
B = bValue
C = cValue
D = dValue
End Sub
End Class
#Region "Events"
Public Class BlankAttractorEventArgs ' Return Blank Attractor
Inherits EventArgs
Public Property Frame As AttractorFrame
Public Property ThreadNumber As Integer
Public Property FileNumber As Integer
Public Property StatusType As Integer
Sub New(blankFileNumber As Integer, blankThreadNumber As Integer, blankType As Integer, blankFrame As AttractorFrame)
FileNumber = blankFileNumber
StatusType = blankType
ThreadNumber = blankThreadNumber
Frame = blankFrame
End Sub
End Class
Public Class LogEntryEventArgs ' Log Event
Inherits EventArgs
Public Property EntryType As String
Public Property Descriptor As String
Sub New(logType As String, logDescriptor As String)
EntryType = logType
Descriptor = logDescriptor
End Sub
End Class
Public Class AttractorFinishedEventArgs ' Allocate new work on completion of frame
Inherits EventArgs
Public Property ThreadNumber As Integer
Sub New(attractorThreadNumber As Integer)
ThreadNumber = attractorThreadNumber
End Sub
End Class
#End Region
Class HSBColour
' Colour Conversion from HSB to RGB - http://www.cs.rit.edu/~ncs/color/t_convert.html
Public Property H As Double
Public Property S As Double
Public Property V As Double
Sub New(Optional Hue As Double = 0, Optional Sat As Double = 0, Optional Bright As Double = 0)
H = Hue
S = Sat
V = Bright
End Sub
Function HSBToRGB() As Drawing.Color
Dim R, G, B As Double
Dim i As Double
Dim f, p, q, t As Double
If S <= 0 Then
Return Drawing.Color.FromArgb(0, 0, 0)
ElseIf V <= 0 Then
Return Drawing.Color.FromArgb(0, 0, 0)
End If
If H > 360 Then H -= 360
H /= 60
i = Math.Floor(H)
f = H - i
p = V * (1 - S)
q = V * (1 - S * f)
t = V * (1 - S * (1 - f))
Select Case i
Case Is = 0
R = V
G = t
B = p
Case Is = 1
R = q
G = V
B = p
Case Is = 2
R = p
G = V
B = t
Case Is = 3
R = p
G = q
B = V
Case Is = 4
R = t
G = p
B = V
Case Else
R = V
G = p
B = q
End Select
Return Drawing.Color.FromArgb(CInt(R * 255), CInt(G * 255), CInt(B * 255))
End Function
End Class
Namespace AttractorResources ' String Literals
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Class AttractorStrings
Private Shared resourceMan As Global.System.Resources.ResourceManager
Private Shared resourceCulture As Global.System.Globalization.CultureInfo
<Global.System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")> _
Friend Sub New()
MyBase.New()
End Sub
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Shared ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("AttractorCore.AttractorStrings", GetType(AttractorStrings).Assembly)
resourceMan = temp
End If
Return resourceMan
End Get
End Property
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Shared Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set(value As Global.System.Globalization.CultureInfo)
resourceCulture = value
End Set
End Property
Friend Shared ReadOnly Property Frame() As String
Get
Return "Frame "
End Get
End Property
Friend Shared ReadOnly Property Thread() As String
Get
Return " - Thread "
End Get
End Property
Friend Shared ReadOnly Property Time() As String
Get
Return " - Time Elapsed: "
End Get
End Property
Friend Shared ReadOnly Property Density() As String
Get
Return " - " & "Density Average: "
End Get
End Property
Friend Shared ReadOnly Property LogMax() As String
Get
Return " - " & "Log MaxDense: "
End Get
End Property
End Class
End Namespace
' Attractor Animation Creation
' Create animation by generating values for subsequent frames, handling 2 threads and blank frames
Option Strict On
Option Explicit On
Option Infer On
Imports System
Imports Microsoft.VisualBasic
Imports AttractorCore.My.Resources ' For String Literals
<Assembly: CLSCompliant(True)>
Module Run
Dim Current As Integer = 0 ' Current Frame - Array Offset
Dim LastChange As Integer = 0 ' When the last block turned (Due to reaching boundaries, multiple blank frames or block depletion)
Dim LastDirection As Integer = 0 ' The last tried direction (to save CPU time when looking for path - smoother animation)
Dim EndFrame As Integer = 5400 ' Final Frame (Number)
Dim IArray(10000, 4) As Double ' a,b,c,d,Direction - Extra Indexes are for the Final block of 300
Const Iterations As Integer = 10000 * 3000 ' The number of times the x/y values of attractor will be incremented
Const BlockSize As Integer = 600 ' Size of block (For use in detecting the number of successful frames before a blank frame is reached)
Dim BlockCountdown As Integer = BlockSize ' Countdown before Changing Direction
Dim LogPath As String = "Log.txt" ' Path of log file
Sub Main()
System.Threading.Thread.CurrentThread.CurrentUICulture = New Globalization.CultureInfo("en-US")
'Dim At As New Attractor ' Without Multithreading or blank detection
'At.deJong(-2.5, 4.73, -4.83, 1.03, 10000 * 3000, 100) ' Blank
'At.deJong(-2.5, 4.69, -4.79, 1.03, 10000 * 3000, 0) ' Good
Console.WriteLine(AttractorStrings.Attractor & AttractorStrings.Space & My.Application.Info.Version.ToString)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Init, AttractorStrings.Start & My.Application.Info.Version.ToString))
InitaliseAttractors() ' Start
Console.ReadLine()
End Sub
Sub LogEvent(sender As Object, e As LogEntryEventArgs) ' Write Log to File
Try
My.Computer.FileSystem.WriteAllText(LogPath, DateTime.Now.ToLongTimeString & AttractorStrings.LeftBracket & e.EntryType & AttractorStrings.RightBracket & e.Descriptor & Environment.NewLine, True)
Catch ex As System.IO.IOException
Exit Sub
End Try
End Sub
Dim td As New Attractor : Dim td2 As New Attractor ' Declare 2 Instances
Dim HandlersAdded As Boolean = False ' Handlers for detecting Events
Sub ResetBlinky(sender As Object, e As EventArgs) ' Triggered on Successful Frame (i.e Not Blank)
Blinky = 0 ' Reset Threshold for Blank Frames
End Sub
Sub InitaliseAttractors(Optional Type As Integer = 0) ' Start/Restart Threads
CalculateNewBlock() ' Calculate Block
If Type = 1 Then ' Reset offset due to increment by AllocateWork Subroutine
If Current <> 0 Then
Current -= 1
End If
End If
For Each file As String In System.IO.Directory.GetFiles(My.Application.Info.DirectoryPath)
If file.Contains(".png") Then
If CInt(System.IO.Path.GetFileName(file).Split(CChar("_"))(0)) >= Current + 1 Then
System.IO.File.Delete(file) ' Delete files if segment is not long enough - smoother animation
End If
End If
Next
If HandlersAdded = False Then
AddHandler td.BlankAttractor, AddressOf BlankCaller : AddHandler td2.BlankAttractor, AddressOf BlankCaller
AddHandler td.AttractorFinished, AddressOf WorkCaller : AddHandler td2.AttractorFinished, AddressOf WorkCaller
AddHandler td.RaiseLogEntry, AddressOf LogEvent : AddHandler td2.RaiseLogEntry, AddressOf LogEvent
AddHandler td.Success, AddressOf ResetBlinky : AddHandler td2.Success, AddressOf ResetBlinky
HandlersAdded = True ' Handlers for Blank/Work Completion
End If
td.AssignThread(1) ' Assign Number/ID to thread
AllocateWork(1) ' Allocate work to thread ID #
Threading.Thread.Sleep(200) ' Race Condition
td2.AssignThread(2)
AllocateWork(2)
End Sub
Const Boundary As Double = 4.5 ' Boundary values for a,b,c,d of deJong
Dim InFin As Integer = 0 ' Reduce chance of Infinite Loops
Dim rnd As New Random
Sub CalculateNewBlock() ' Generate values for next block, taking into account blanks and # of frames since last block was generated
If BlockCountdown > (BlockSize - 60) And InFin < 75 And Current <> 0 Then
' Last segment was not enough - reset and recalculate
Current = LastChange
Console.WriteLine(AttractorStrings.Sudden & LastChange)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Block, AttractorStrings.Sudden & LastChange))
End If
Dim PrevA, PrevB, PrevC, PrevD As Double
If Current = 0 Or Current = 1 Or Current = 2 Then ' Starting a,b,c,d values
PrevA = -2.5 : PrevB = 3.87 : PrevC = -3.97 : PrevD = 1.03
Current = 0
Else ' -1 from Current (offset) to create continuous blocks
PrevA = IArray(Current - 1, 0) : PrevB = IArray(Current - 1, 1)
PrevC = IArray(Current - 1, 2) : PrevD = IArray(Current - 1, 3)
End If
Dim Ina, Inb, Inc, Ind As Double ' Change in a,b,c,d values
Dim Direction As Integer = 0
' Determine "Direction" of Next Block using Random -> +/- change in a,b,c,d values
Select Case rnd.Next(0, 24)
' A and B
Case Is = 0 : Ina = 0.02 : Inb = 0.02 : Direction = 1
Case Is = 1 : Ina = -0.02 : Inb = -0.02 : Direction = 2
Case Is = 2 : Ina = -0.02 : Inb = +0.02 : Direction = 3
Case Is = 3 : Ina = +0.02 : Inb = -0.02 : Direction = 4
' A and C
Case Is = 4 : Ina = 0.02 : Inc = 0.02 : Direction = 5
Case Is = 5 : Ina = -0.02 : Inc = -0.02 : Direction = 6
Case Is = 6 : Ina = -0.02 : Inc = +0.02 : Direction = 7
Case Is = 7 : Ina = +0.02 : Inc = -0.02 : Direction = 8
' A and D
Case Is = 8 : Ina = 0.02 : Ind = 0.02 : Direction = 9
Case Is = 9 : Ina = -0.02 : Ind = -0.02 : Direction = 10
Case Is = 10 : Ina = -0.02 : Ind = +0.02 : Direction = 11
Case Is = 11 : Ina = +0.02 : Ind = -0.02 : Direction = 12
' B and C
Case Is = 12 : Inb = 0.02 : Inc = 0.02 : Direction = 13
Case Is = 13 : Inb = -0.02 : Inc = -0.02 : Direction = 14
Case Is = 14 : Inb = -0.02 : Inc = +0.02 : Direction = 15
Case Is = 15 : Inb = +0.02 : Inc = -0.02 : Direction = 16
' B and D
Case Is = 16 : Inb = 0.02 : Ind = 0.02 : Direction = 17
Case Is = 17 : Inb = -0.02 : Ind = -0.02 : Direction = 18
Case Is = 18 : Inb = -0.02 : Ind = +0.02 : Direction = 19
Case Is = 19 : Inb = +0.02 : Ind = -0.02 : Direction = 20
' C and D
Case Is = 20 : Inc = 0.02 : Ind = 0.02 : Direction = 21
Case Is = 21 : Inc = -0.02 : Ind = -0.02 : Direction = 22
Case Is = 22 : Inc = -0.02 : Ind = +0.02 : Direction = 23
Case Is = 23 : Inc = +0.02 : Ind = -0.02 : Direction = 24
End Select
If LastDirection = Direction Then ' Calculate New Direction
Console.WriteLine(AttractorStrings.Direction)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Block, AttractorStrings.Direction))
CalculateNewBlock()
Exit Sub
End If
For i = 0 To BlockSize ' Generate new block
PrevA += Ina
PrevB += Inb
PrevC += Inc
PrevD += Ind
If PrevA > Boundary Or PrevB > Boundary Or PrevC > Boundary Or PrevD > Boundary Or PrevA < -Boundary Or PrevB < -Boundary Or PrevC < -Boundary Or PrevD < -Boundary Then
If i < 60 And InFin < 75 Then ' Ensure there are 60 frames before direction change due to boundary values
Console.WriteLine(AttractorStrings.Boundary & Direction)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Block, AttractorStrings.Boundary & Direction))
InFin += 1
CalculateNewBlock()
Exit Sub
End If
End If
PrevA = Math.Round(PrevA, 2)
PrevB = Math.Round(PrevB, 2)
PrevC = Math.Round(PrevC, 2)
PrevD = Math.Round(PrevD, 2)
For f = 0 To BlankArray.Count - 1 ' Use BlankArray to reduce time
If BlankArray(f).A = PrevA And BlankArray(f).B = PrevB And BlankArray(f).C = PrevC And BlankArray(f).D = PrevD And (i < 2 And InFin < 75) Then
If i < 2 And InFin < 75 Then ' so 0 or 1 - the 2 immediate frames
Console.WriteLine(AttractorStrings.Blank & Direction)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Block, AttractorStrings.Blank & Direction))
InFin += 1
CalculateNewBlock()
Exit Sub
End If
End If
Next
' Save into Array
IArray(Current + i, 0) = PrevA
IArray(Current + i, 1) = PrevB
IArray(Current + i, 2) = PrevC
IArray(Current + i, 3) = PrevD
IArray(Current + i, 4) = Direction
Next
BlockCountdown = BlockSize ' Reset Block Countdown
Console.WriteLine(AttractorStrings.NewBlock & Direction)
LogEvent(Nothing, New LogEntryEventArgs(AttractorStrings.Block, AttractorStrings.NewBlock & Direction))
LastChange = Current : LastDirection = Direction
InFin = 0
End Sub
Dim CallerArray As New System.Collections.Generic.List(Of System.Threading.Thread) ' Storing threads
Sub BlankCaller(sender As Object, e As BlankAttractorEventArgs) ' Called when Attractor Class detects blank/dark frame
Try
If CallerArray.Count <> 0 Then
For i = 0 To CallerArray.Count - 1
Do Until CallerArray(i).IsAlive = False : Loop
Next
End If
Catch ex As IndexOutOfRangeException
End Try
' Wait until all previous threads are finished, then execute AttractorBlank using returned parameters
Dim Caller As System.Threading.Thread = New System.Threading.Thread(
Sub()
AttractorBlank(e.FileNumber, e.StatusType, e.Frame.A, e.Frame.B, e.Frame.C, e.Frame.D, e.ThreadNumber)
End Sub)
CallerArray.Add(Caller)
Caller.Start()
End Sub
Dim BlankArray As New System.Collections.Generic.List(Of AttractorFrame) ' Stores blank frames for lookup
Private Sub deJongThreadBlank() ' Call deJong without aborting threads
Select Case An.TN
Case Is = 1
td.Dejong(An.A, An.B, An.C, An.D, Iterations, An.FN)
Case Is = 2
td2.Dejong(An.A, An.B, An.C, An.D, Iterations, An.FN)
End Select
End Sub
Dim BlankAttractorT1 As Integer = 0 ' Variation to previous blank frame
Dim BlankAttractorT2 As Integer = 0
Dim An As New BlankFramesRedo(0, 0, 0, 0, 0, 0) ' Next frame to calculate due to previous blank frames
Dim Blinky As Integer = 0 ' Number of consecutive blank frames
Sub AttractorBlank(ByVal FileNumber As Integer, ByVal Type As Integer, ByVal A As Double, ByVal B As Double, ByVal C As Double, ByVal D As Double, ByVal TNum As Integer)
BlankArray.Add(New AttractorFrame(A, B, C, D)) ' Add blank frame for lookup
Console.WriteLine(AttractorStrings.Frame & FileNumber & AttractorStrings.IsBlank)
LogEvent(Nothing, New LogEntryEventArgs("Blank Frame", AttractorStrings.Frame & FileNumber & AttractorStrings.IsBlank & A & AttractorStrings.Comma & B & AttractorStrings.Comma & C & AttractorStrings.Comma & D & AttractorStrings.Type & Type))
If BlankAttractorT1 >= 4 Or BlankAttractorT2 >= 4 Then ' Frame/Surrounding Frames are truly blank
If Blinky = 4 Then ' Threshold Reached
If WorkerThreads.Count <> 0 Then
For i = 0 To WorkerThreads.Count - 1
WorkerThreads(i).Abort() ' Stop all running threads
Do Until WorkerThreads(i).IsAlive = False : Loop
Next
End If
WorkerThreads.Clear() ' Clear Array
Dim LowestFrame As Integer = 0 ' Find lowest frame being rendered
If td.FNumber < td2.FNumber Then
LowestFrame = td.FNumber
Else
LowestFrame = td2.FNumber
End If
Current = LowestFrame ' Rollback offset
For Each file As String In System.IO.Directory.GetFiles(My.Application.Info.DirectoryPath)
If file.Contains(".png") Then ' Rollback offset if there's a gap
Current = CInt(System.IO.Path.GetFileName(file).Split(CChar("_"))(0))
End If
Next
InitaliseAttractors(1) ' Init Threads
Exit Sub
End If
' Note - This code contains logic error - Blinky is not reset
WorkCaller(Nothing, New AttractorFinishedEventArgs(TNum)) ' Next Frame in Array
Blinky += 1 ' Increment # of Consecutive Blank Frames
Exit Sub
End If
Dim Ina, Inb, Inc, Ind As Double
Select Case IArray(FileNumber, 4) ' Use Last Direction to determine surrounding frame. Attempt to skip over blank frames
' A and B
Case Is = 1 : Ina = 0.02 : Inb = 0.02
Case Is = 2 : Ina = -0.02 : Inb = -0.02
Case Is = 3 : Ina = -0.02 : Inb = +0.02
Case Is = 4 : Ina = +0.02 : Inb = -0.02
' A and C
Case Is = 5 : Ina = 0.02 : Inc = 0.02
Case Is = 6 : Ina = -0.02 : Inc = -0.02
Case Is = 7 : Ina = -0.02 : Inc = +0.02
Case Is = 8 : Ina = +0.02 : Inc = -0.02
' A and D
Case Is = 9 : Ina = 0.02 : Ind = 0.02
Case Is = 10 : Ina = -0.02 : Ind = -0.02
Case Is = 11 : Ina = -0.02 : Ind = +0.02
Case Is = 12 : Ina = +0.02 : Ind = -0.02
' B and C
Case Is = 13 : Inb = 0.02 : Inc = 0.02
Case Is = 14 : Inb = -0.02 : Inc = -0.02
Case Is = 15 : Inb = -0.02 : Inc = +0.02
Case Is = 16 : Inb = +0.02 : Inc = -0.02
' B and D
Case Is = 17 : Inb = 0.02 : Ind = 0.02
Case Is = 18 : Inb = -0.02 : Ind = -0.02
Case Is = 19 : Inb = -0.02 : Ind = +0.02
Case Is = 20 : Inb = +0.02 : Ind = -0.02
' C and D
Case Is = 21 : Inc = 0.02 : Ind = 0.02
Case Is = 22 : Inc = -0.02 : Ind = -0.02
Case Is = 23 : Inc = -0.02 : Ind = +0.02
Case Is = 24 : Inc = +0.02 : Ind = -0.02
End Select
Select Case TNum ' Use ThreadNumber to Increment Values
Case Is = 1 ' Thread 1
BlankAttractorT1 += 1
If BlankAttractorT1 = 1 Then
Ina = Ina / 4 : Inb = Inb / 4 : Inc = Inc / 4 : Ind = Ind / 4
ElseIf BlankAttractorT1 = 2 Then
Ina = Ina / 2 : Inb = Inb / 2 : Inc = Inc / 2 : Ind = Ind / 2
ElseIf BlankAttractorT1 = 3 Then
Ina = Ina / 2 * 1.5 : Inb = Inb / 2 * 1.5 : Inc = Inc / 2 * 1.5 : Ind = Ind / 2 * 1.5
ElseIf BlankAttractorT1 = 4 Then
Ina = Ina / 2 * 3 : Inb = Inb / 2 * 3 : Inc = Inc / 2 * 3 : Ind = Ind / 2 * 3
End If
Case Is = 2 ' Thread 2
BlankAttractorT2 += 1
If BlankAttractorT2 = 1 Then
Ina = Ina / 4 : Inb = Inb / 4 : Inc = Inc / 4 : Ind = Ind / 4
ElseIf BlankAttractorT2 = 2 Then
Ina = Ina / 2 : Inb = Inb / 2 : Inc = Inc / 2 : Ind = Ind / 2
ElseIf BlankAttractorT2 = 3 Then
Ina = Ina / 2 * 1.5 : Inb = Inb / 2 * 1.5 : Inc = Inc / 2 * 1.5 : Ind = Ind / 2 * 1.5
ElseIf BlankAttractorT2 = 4 Then
Ina = Ina / 2 * 3 : Inb = Inb / 2 * 3 : Inc = Inc / 2 * 3 : Ind = Ind / 2 * 3
End If
End Select
' Set values of AN for deJongThreadBlank
An.A = IArray(FileNumber, 0) + Ina
An.B = IArray(FileNumber, 1) + Inb
An.C = IArray(FileNumber, 2) + Inc
An.D = IArray(FileNumber, 3) + Ind
An.TN = TNum
An.FN = FileNumber
' Start deJongThreadBlank -> For surrounding Frames
Dim Caller As System.Threading.Thread = New System.Threading.Thread(AddressOf deJongThreadBlank)
WorkerThreads.Add(Caller)
Caller.Start()
End Sub
Function IsFinished() As Boolean ' Check to see if all frames are done
If Current = EndFrame Then
Return True
End If
Return False
End Function
Dim WorkerThreads As New System.Collections.Generic.List(Of Threading.Thread)
Dim WorkCallerThreads As New System.Collections.Generic.List(Of Threading.Thread)
Sub WorkCaller(sender As Object, e As AttractorFinishedEventArgs) ' Allocate Work
Try
If WorkCallerThreads.Count <> 0 Then
For i = 0 To WorkCallerThreads.Count - 1
Do Until WorkCallerThreads(i).IsAlive = False : Loop
Next
End If
Catch ex As IndexOutOfRangeException
End Try
Dim Caller As System.Threading.Thread = New System.Threading.Thread(Sub() AllocateWork(e.ThreadNumber))
WorkCallerThreads.Add(Caller)
Caller.Start()
End Sub
Sub AllocateWork(THNum As Integer) ' Allocate Work once Thread is Finished
If BlockCountdown = 0 Then
CalculateNewBlock()
End If
BlockCountdown -= 1 ' Decrease Block Countdown
If IsFinished() = True Then ' Check to see if all frames are rendered
LogEvent(Nothing, New LogEntryEventArgs("Fin", "All allocated work has been finished."))
Exit Sub
End If
Select Case THNum ' Start new Threads
Case Is = 1
BlankAttractorT1 = 0
Current += 1
Dim ta As System.Threading.Thread
ta = New System.Threading.Thread(AddressOf deJongThread1)
ta.IsBackground = True
ta.Start()
WorkerThreads.Add(ta)
Case Is = 2
BlankAttractorT2 = 0
Current += 1
Dim ta As System.Threading.Thread
ta = New System.Threading.Thread(AddressOf deJongThread2)
ta.IsBackground = True
ta.Start()
WorkerThreads.Add(ta)
End Select
End Sub
Sub CheckValues() ' Check to see if boundaries are reached
If IArray(Current, 0) > Boundary Or IArray(Current, 0) < -Boundary Or IArray(Current, 1) > Boundary Or IArray(Current, 1) < -Boundary Or IArray(Current, 2) > Boundary Or IArray(Current, 2) < -Boundary Or IArray(Current, 3) > Boundary Or IArray(Current, 3) < -Boundary Then
CalculateNewBlock()
End If
End Sub
Private Sub deJongThread1() ' Thread 1
CheckValues()
td.Dejong(IArray(Current, 0), IArray(Current, 1), IArray(Current, 2), IArray(Current, 3), Iterations, Current)
End Sub
Private Sub deJongThread2() ' Thread 2
CheckValues()
td2.Dejong(IArray(Current, 0), IArray(Current, 1), IArray(Current, 2), IArray(Current, 3), Iterations, Current)
End Sub
End Module
Class BlankFramesRedo ' Store surrounding blank frames
Public Property A As Double
Public Property B As Double
Public Property C As Double
Public Property D As Double
Public Property TN As Integer
Public Property FN As Integer
Sub New(aVal As Double, bVal As Double, cVal As Double, dVal As Double, T As Integer, F As Integer)
A = aVal
B = bVal
C = cVal
D = dVal
TN = T
FN = F
End Sub
End Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment