protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (e.KeyCode == Keys.R) { _mandelbrotWindow = MandelbrotPosition.Default; using (MainForm tempForm = new MainForm()) { double xFactor = Size.Width / (double)tempForm.Width, yFactor = Size.Height / (double)tempForm.Height; _mandelbrotWindow.Width *= xFactor; _mandelbrotWindow.Height *= yFactor; } UpdateImageAsync(); } else if (e.KeyCode == Keys.S) { _parallelRendering = false; UpdateImageAsync(); } else if (e.KeyCode == Keys.P) { _parallelRendering = true; UpdateImageAsync(); } }
/// <summary>Renders a mandelbrot fractal.</summary> /// <param name="position">The MandelbrotPosition representing the fractal boundaries to be rendered.</param> /// <param name="imageWidth">The width in pixels of the image to create.</param> /// <param name="imageHeight">The height in pixels of the image to create.</param> /// <param name="parallelRendering">Whether to render the image in parallel.</param> /// <returns>The rendered Bitmap.</returns> public unsafe static Bitmap Create(MandelbrotPosition position, int imageWidth, int imageHeight, CancellationToken cancellationToken, bool parallelRendering) { // The maximum number of iterations to perform for each pixel. Higher number means better // quality but also slower. const int maxIterations = 256; // In order to use the Bitmap ctor that accepts a stride, the stride must be divisible by four. // We're using imageWidth as the stride, so shift it to be divisible by 4 as necessary. if (imageWidth % 4 != 0) { imageWidth = (imageWidth / 4) * 4; } // Based on the fractal bounds, determine its upper left coordinate double left = position.CenterX - (position.Width / 2); double top = position.CenterY - (position.Height / 2); // Get the factors that can be multiplied by row and col to arrive at specific x and y values double colToXTranslation = position.Width / (double)imageWidth; double rowToYTranslation = position.Height / (double)imageHeight; // Create the byte array that will store the rendered color indices int pixels = imageWidth * imageHeight; byte[] data = new byte[pixels]; // initialized to all 0s, which equates to all black based on the default palette // Generate the fractal using the mandelbrot formula : z = z^2 + c // Parallel implementation if (parallelRendering) { var options = new ParallelOptions { CancellationToken = cancellationToken }; Parallel.For(0, imageHeight, options, row => { double initialY = row * rowToYTranslation + top; fixed(byte *ptr = data) { byte *currentPixel = &ptr[row * imageWidth]; for (int col = 0; col < imageWidth; col++, currentPixel++) { Complex c = new Complex(col * colToXTranslation + left, initialY); Complex z = c; for (int iteration = 0; iteration < maxIterations; iteration++) { if (z.Magnitude > 4) { *currentPixel = (byte)iteration; break; } z = (z * z) + c; } } } }); } // Sequential implementation else { for (int row = 0; row < imageHeight; row++) { //cancellationToken.ThrowIfCancellationRequested(); double initialY = row * rowToYTranslation + top; fixed(byte *ptr = data) { byte *currentPixel = &ptr[row * imageWidth]; for (int col = 0; col < imageWidth; col++, currentPixel++) { Complex c = new Complex(col * colToXTranslation + left, initialY); Complex z = c; for (int iteration = 0; iteration < maxIterations; iteration++) { if (z.Magnitude > 4) { *currentPixel = (byte)iteration; break; } z = (z * z) + c; } } } } ; } // Produce a Bitmap from the byte array of color indices and return it fixed(byte *ptr = data) { using (Bitmap tempBitmap = new Bitmap(imageWidth, imageHeight, imageWidth, PixelFormat.Format8bppIndexed, (IntPtr)ptr)) { Bitmap bitmap = tempBitmap.Clone(new Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), PixelFormat.Format8bppIndexed); UpdatePalette(bitmap); return(bitmap); } } }
/// <summary>Renders a mandelbrot fractal.</summary> /// <param name="position">The MandelbrotPosition representing the fractal boundaries to be rendered.</param> /// <param name="imageWidth">The width in pixels of the image to create.</param> /// <param name="imageHeight">The height in pixels of the image to create.</param> /// <param name="parallelRendering">Whether to render the image in parallel.</param> /// <returns>The rendered Bitmap.</returns> public unsafe static Bitmap Create(MandelbrotPosition position, int imageWidth, int imageHeight, CancellationToken cancellationToken, bool parallelRendering) { // The maximum number of iterations to perform for each pixel. Higher number means better // quality but also slower. const int maxIterations = 256; // In order to use the Bitmap ctor that accepts a stride, the stride must be divisible by four. // We're using imageWidth as the stride, so shift it to be divisible by 4 as necessary. if (imageWidth % 4 != 0) imageWidth = (imageWidth / 4) * 4; // Based on the fractal bounds, determine its upper left coordinate double left = position.CenterX - (position.Width / 2); double top = position.CenterY - (position.Height / 2); // Get the factors that can be multiplied by row and col to arrive at specific x and y values double colToXTranslation = position.Width / (double)imageWidth; double rowToYTranslation = position.Height / (double)imageHeight; // Create the byte array that will store the rendered color indices int pixels = imageWidth * imageHeight; byte[] data = new byte[pixels]; // initialized to all 0s, which equates to all black based on the default palette // Generate the fractal using the mandelbrot formula : z = z^2 + c // Parallel implementation if (parallelRendering) { var options = new ParallelOptions { CancellationToken = cancellationToken }; Parallel.For(0, imageHeight, options, row => { double initialY = row * rowToYTranslation + top; fixed (byte* ptr = data) { byte* currentPixel = &ptr[row * imageWidth]; for (int col = 0; col < imageWidth; col++, currentPixel++) { Complex c = new Complex(col * colToXTranslation + left, initialY); Complex z = c; for (int iteration = 0; iteration < maxIterations; iteration++) { if (z.Magnitude > 4) { *currentPixel = (byte)iteration; break; } z = (z * z) + c; } } } }); } // Sequential implementation else { for (int row = 0; row < imageHeight; row++) { cancellationToken.ThrowIfCancellationRequested(); double initialY = row * rowToYTranslation + top; fixed (byte* ptr = data) { byte* currentPixel = &ptr[row * imageWidth]; for (int col = 0; col < imageWidth; col++, currentPixel++) { Complex c = new Complex(col * colToXTranslation + left, initialY); Complex z = c; for (int iteration = 0; iteration < maxIterations; iteration++) { if (z.Magnitude > 4) { *currentPixel = (byte)iteration; break; } z = (z * z) + c; } } } }; } // Produce a Bitmap from the byte array of color indices and return it fixed (byte* ptr = data) { using (Bitmap tempBitmap = new Bitmap(imageWidth, imageHeight, imageWidth, PixelFormat.Format8bppIndexed, (IntPtr)ptr)) { Bitmap bitmap = tempBitmap.Clone(new Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), PixelFormat.Format8bppIndexed); UpdatePalette(bitmap); return bitmap; } } }