Last active
September 25, 2021 17:51
-
-
Save palladin/8046053 to your computer and use it in GitHub Desktop.
Mandelbrot set with LINQ
This file contains hidden or 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
// http://msmvps.com/blogs/jon_skeet/archive/2008/02/26/visualising-the-mandelbrot-set-with-linq-yet-again.aspx | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Windows.Forms; | |
using System.Drawing; | |
using System.Drawing.Imaging; | |
using System.Diagnostics; | |
using LinqOptimizer.CSharp; | |
namespace LinqMandelbrot | |
{ | |
public static class Program | |
{ | |
const int ImageWidth = 1000; | |
const int ImageHeight = (int)(SampleHeight * ImageWidth / SampleWidth); | |
[STAThread] | |
static void Main() | |
{ | |
Application.EnableVisualStyles(); | |
Application.SetCompatibleTextRenderingDefault(false); | |
var query = from row in heightArray.AsParallelQueryExpr() | |
from col in widthArray | |
// Work out the initial complex value from the row and column | |
let c = new Complex((col * SampleWidth) / ImageWidth + OffsetX, | |
(row * SampleHeight) / ImageHeight + OffsetY) | |
// Work out the number of iterations | |
let count = EnumerableEx.Generate(c, x => x.SquareLength < 4, x => x * x + c, x => x) | |
.Take(MaxIterations) | |
.Count() | |
// Map that to an appropriate byte value | |
select (byte)(count == MaxIterations ? 0 : (count % 255) + 1); | |
var resultTuple = Measure(() => query.ToArray().Run()); | |
DisplayImage(resultTuple.Item1, resultTuple.Item2.ToString()); | |
} | |
#region Details | |
const int MaxIterations = 200; | |
const double SampleWidth = 3.2; | |
const double SampleHeight = 2.5; | |
const double OffsetX = -2.1; | |
const double OffsetY = -1.25; | |
public static int[] heightArray = Enumerable.Range(0, ImageHeight).ToArray(); | |
public static int[] widthArray = Enumerable.Range(0, ImageWidth).ToArray(); | |
public static class EnumerableEx | |
{ | |
public static IEnumerable<R> Generate<T, R>(T start, Func<T, bool> cond, Func<T, T> step, Func<T, R> resultSelector) | |
{ | |
T value = start; | |
while (cond(value)) | |
{ | |
yield return resultSelector(value); | |
value = step(value); | |
} | |
} | |
} | |
static void DisplayImage(byte[] data, string text) | |
{ | |
unsafe | |
{ | |
fixed (byte* ptr = data) | |
{ | |
IntPtr scan0 = new IntPtr(ptr); | |
Bitmap bitmap = new Bitmap(ImageWidth, ImageHeight, ImageWidth, PixelFormat.Format8bppIndexed, scan0); | |
ColorPalette palette = bitmap.Palette; | |
palette.Entries[0] = Color.Black; | |
for (int i = 1; i < 256; i++) | |
{ | |
palette.Entries[i] = Color.FromArgb((i * 7) % 256, (i * 7) % 256, 255); | |
} | |
bitmap.Palette = palette; | |
PictureBox pb = new PictureBox(); | |
pb.SizeMode = PictureBoxSizeMode.AutoSize; | |
pb.Image = bitmap; | |
Panel panel = new Panel(); | |
panel.Controls.Add(pb); | |
panel.AutoScroll = true; | |
panel.Dock = DockStyle.Fill; | |
Form form = new Form(); | |
form.FormBorderStyle = FormBorderStyle.Fixed3D; | |
form.Controls.Add(panel); | |
form.ClientSize = bitmap.Size; | |
form.Text = text; | |
Application.Run(form); | |
} | |
} | |
} | |
static Tuple<T, TimeSpan> Measure<T>(Func<T> func) | |
{ | |
var watch = new Stopwatch(); | |
watch.Start(); | |
T result = func(); | |
return Tuple.Create(result, watch.Elapsed); | |
} | |
public struct Complex | |
{ | |
readonly double real; | |
readonly double imaginary; | |
public Complex(double real, double imaginary) | |
{ | |
this.real = real; | |
this.imaginary = imaginary; | |
} | |
public static Complex operator +(Complex c1, Complex c2) | |
{ | |
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary); | |
} | |
public static Complex operator *(Complex c1, Complex c2) | |
{ | |
return new Complex(c1.real * c2.real - c1.imaginary * c2.imaginary, | |
c1.real * c2.imaginary + c2.real * c1.imaginary); | |
} | |
public double SquareLength | |
{ | |
get { return real * real + imaginary * imaginary; } | |
} | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment