Fractals are infinitely self-similar, iterated and detailed mathematical constructs. Plotting them into an image can produce fantastic results. One type of Fractal is an Orbital Fractal or an Escape-Time Fractal, in which each point in space is calculated from a formula. One type of Orbital Fractal is the Mira Fractal. The Mira equation was developed at the CERN research centre in 1980 by I. Gumowski and C. Mira. It was not designed to create fractals, but to calculate the trajectories of sub-atomic particles. The algorithm used in this script originally came from ‘Fractals’ by Hans Lauwerier.

Here are some images generated from the below script –

Mira_20131123_172513

Mira_20131119_202343

Mira_20131123_165657

Mira_20131120_173238

Mira_20131122_175334

There are two values which control how the fractal is generated. I made a WinForms Form with TrackBar controls to provide those options. I setup the Main Form and defined some Global Values.

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Main Form
$mainForm = New-Object Windows.Forms.Form
$mainForm.BackColor = "White"
$mainForm.Font = “Comic Sans MS,8.25"
$mainForm.Text = "Mira Orbital Fractal"
$mainForm.size = "500,260"

# Global Values
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$global:colorsValue = 0
$global:iterationsValue = 0

I next setup the TrackBars defining thier orientation, location, size and tick properties. Moving the TrackBar feeds the counter on the Label using the valueChanged Event. The LargeChange and SmallChange properties move the pointer along the TrackBar like a tab when clicking on the bar. I then set the inital values for the TrackBar. The other properties and the Event Handler I discussed in a previous WinForms TrackBar blog.

# Iterations TrackBar
$iterationsTrackBar = New-Object Windows.Forms.TrackBar
$iterationsTrackBar.Location = "70,15"
$iterationsTrackBar.Orientation = "Horizontal"
$iterationsTrackBar.Width = 350
$iterationsTrackBar.Height = 40
$iterationsTrackBar.LargeChange = 25000
$iterationsTrackBar.SmallChange = 5000
$iterationsTrackBar.TickFrequency = 5000
$iterationsTrackBar.TickStyle = "TopLeft"
$iterationsTrackBar.SetRange(5000, 150000)
$iterationsTrackBar.Value = 30000
$iterTrackBarValue = 30000
#Iterations TrackBar Event Handler
$iterationsTrackBar.add_ValueChanged({
    $iterTrackBarValue = $iterationsTrackBar.Value
    $iterationsLabel.Text = "Iterations ($iterTrackBarValue)"
    $global:iterationsValue = $iterTrackBarValue
})
$mainForm.Controls.add($iterationsTrackBar)

# Colors Change TrackBar
$colorsTrackBar = New-Object Windows.Forms.TrackBar
$colorsTrackBar.Location = "70,130"
$colorsTrackBar.Orientation = "Horizontal"
$colorsTrackBar.Width = 350
$colorsTrackBar.Height = 40
$colorsTrackBar.LargeChange = 5000
$colorsTrackBar.SmallChange = 1000
$colorsTrackBar.TickFrequency = 1000
$colorsTrackBar.TickStyle = "BottomRight"
$colorsTrackBar.SetRange(1000, 20000)
$colorsTrackBarValue = 3000
$colorsTrackBar.Value = 3000
#Colors TrackBar Event Handler
$colorsTrackBar.add_ValueChanged({
$colorsTrackBarValue = $colorsTrackBar.Value
    $colorsLabel.Text = "Color Change ($colorsTrackBarValue)"
    $global:colorsValue = $colorsTrackBarValue
})
$mainForm.Controls.add($colorsTrackBar)

I then setup the Labels which provide a title for the TrackBars and show the counters.

# Iterations Label
$iterationsLabel = New-Object System.Windows.Forms.Label
$iterationsLabel.Location = "170,60"
$iterationsLabel.Size = "120,23"
$iterationsLabel.Text = "Iterations ($iterTrackBarValue)"
$mainForm.Controls.Add($iterationsLabel)

# Colors Label
$colorsLabel = New-Object System.Windows.Forms.Label
$colorsLabel.Location = "170,100"
$colorsLabel.Size = "160,23"
$colorsLabel.Text = "Color Change Point ($colorsTrackBarValue)"
$mainForm.Controls.Add($colorsLabel)

# Line Label
$lineLabel = New-Object System.Windows.Forms.Label
$lineLabel.Location = "170,75"
$lineLabel.Size = "150,20"
$lineLabel.Text = "______________________________________"
$mainForm.Controls.Add($lineLabel)

The “Plot” Button calls the PlotIt Function which will draw the image.

# Plot Button
$plotButton = New-Object System.Windows.Forms.Button
$plotButton.Location = "120,185"
$plotButton.Size = "75,23"
$plotButton.Text = "Plot"
$plotButton.add_Click({PlotIt})
$mainForm.Controls.Add($plotButton)

To plot the fractal I first define the bitmap image. I set the backgroup of that image to black. I write a line to the host to show processing has started.

# Plot the Fractal
Function PlotIt {
    Write-Host "Running . . ."

    # Output Bitmap Image
    $bitmap = New-Object System.Drawing.Bitmap(1024, 768)
    $bitmapGraphics = [System.Drawing.Graphics]::FromImage($bitmap)
    $bitmapGraphics.Clear("black")

The values used in the fractal formula are initialized. A Random component is setup so all the fractals will be unique.

    $a = (Get-Random -minimum .0001 -maximum .9999)
    $b = .9998
    $c = 2-(2*$a)
    $x = 0
    $y = 12.1
    $w = (($a*$x)+($c*$x*$x))/(1+($x*$x))

The values which control the appearance are setup. The Multiplier resizes the image from the tiny format the formula generates. At a 25 $multiplier most fractals are full size within the image but some will span the image boundary and so be partially cut off. The $colorChange value controls at which interation the color value changes during processing. When the colors change, a proessing status line is written to the host. The $iterations value control how many cycles are ran. The image is generated from the outside to the inside so using a very high number of iterations will result in more “solid center(s)” in the fractal. After much over 150k there isn’t any significant change in the image since those few pixels have all been colored. You can keep running higher iterations and more detail will be generated, however at this resolution it is not visible. There is not a limit to the iterations, which gives Mira it’s Fractal Dimension. A small number will result in more “airy” images without “solid” sections. The below image was generated at 15k interations changing colors every 1000 cycles to show the difference.

    $multiplier = 25
    $colorChange = $global:colorsValue
    $maxIterations = $global:iterationsValue

Mira_20131123_185325

I initatize the counter and setup the centering values. The original formula uses a Cartesian coordinates system for plotting the points. That places point 0,0 in the center of the screen. But for this bitmap image 0,0 is the upper left corner. So I add half the screen, minus the original size, back to each value on each side to (generally) center it. I select random values for the first color.

    $counter = 1
    $xCentering = 470
    $yCentering = 380
    $red =   (Get-Random -minimum 0 -maximum 255)
    $green = (Get-Random -minimum 0 -maximum 255)
    $blue =  (Get-Random -minimum 0 -maximum 255)

I initiate the While loop, incrementing the $counter and testing for $colorChange. If $colorChange then I write a line to the host and set a random color for the next cycles.
The pixels are then expanded with $multiplier and centered (relatively) within the bitmp. The pixels are tested to fit within the bitmap and the pixel is drawn with SetPixel Method of the System.Drawing.Bitmap Class. After the pixel has been painted the next round of fractal calculation is processed and the While loop continues.

    while ($counter -le $maxIterations) { $counter++
        if (($counter % $colorChange) -eq 0) {
            Write-Host $counter "Cycles"
            $red =   (Get-Random -minimum 0 -maximum 255)
            $green = (Get-Random -minimum 0 -maximum 255)
            $blue =  (Get-Random -minimum 0 -maximum 255)
        }
        $xPixel = ($x * $multiplier) + $xCentering
        $yPixel = ($y * $multiplier) + $yCentering
        if ($xPixel -ge 0) {
            if ($yPixel -ge 0) {
                if ($xPixel -le 1023) {
                    if ($yPixel -le 767) {
                        $bitmap.SetPixel($xPixel, $yPixel, [System.Drawing.Color]::FromArgb($red, $green, $blue))
                    }
                }
            }
        }
        $z = $x
        $x = ($b*$y)+$w
        $u = $x*$x
        $w = ($a*$x)+($c*$u)/(1+$u)
        $y = $w-$z
    }

When the fractal has been fully plotted the file is written to the disk. I select as the file location the same folder where the script resides. The file name is made unique by postpending the date and time to the name “Mira”.
The bitmap is displayed from the newly created file using the default image viewer on the system by calling Invoke-Item.
I then dispose of the $bitmap COM objects to clear them and write a completion line to the host.

    $outFile = $scriptPath + "\"  + "Mira_" + (Get-Date -UFormat %Y%m%d_%H%M%S) + ".bmp"
    $bitmap.Save($outFile)
    Invoke-Item $outFile
    $bitmap.Dispose()
    $bitmapGraphics.Dispose()
    Write-Host "Complete"
}

The last step is an Exit Button to close the Main Form.

# Exit Button
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Location = "300,185"
$exitButton.Size = "75,23"
$exitButton.Text = "Exit"
$exitButton.add_Click({$mainForm.close()})
$mainForm.Controls.Add($exitButton)

The Main Form –

Mira<

Download – Mira.ps1

Advertisements