-
-
Save YC/8484eb73b3b66959308d to your computer and use it in GitHub Desktop.
Innumerable - Peter de Jong Attractor & Animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' "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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' 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