public FractalSettings(IFractalAlgorithm algorithm, int screenWidth, int screenHeight, Rectangle <double> fractalRect, int maxIterations) { this.Algorithm = algorithm; this.FractalRect = fractalRect; this.MaxIterations = maxIterations; this.ScreenWidth = screenWidth; this.ScreenHeight = screenHeight; }
public void RegisterFractalAlgorithm(IFractalAlgorithm algorithm) { this.algorithms.Add(algorithm); }
/// <summary> /// Draws the specified fractal algorithm. /// </summary> /// <param name="color">The color parameter.</param> /// <param name="motion">The motion parameter.</param> /// <param name="algorithm">The fractal algorithm.</param> /// <param name="techniques">The coloring techniques.</param> /// <param name="combinationFunction">The combination function.</param> /// <param name="maxParallelism">The maximum parallelism. By default will take all the CPUs available.</param> /// <returns>The final bitmap.</returns> public byte[] Draw( double color, double motion, IFractalAlgorithm algorithm, IEnumerable <IColoringTechnique> techniques, Func <Color[], Color> combinationFunction, int maxParallelism = -1) { // if the max parallelism is not provided, the system will try to create // one thread per logical processor available. if (maxParallelism <= 0) { maxParallelism = this.GetMaxParallelism(); } // creates an memory array for all the pixels in the final drawing. var bitmapArray = new byte[this.Width * this.Height * 4]; // separates the image array into smaller slices, once per thread. The idea is to // calculate sectors of the fractal in parallel. var memorySlices = bitmapArray.SliceArray(maxParallelism); // converts the enumeration to a list just to prevent multiple enumerations later. var colorTechniques = techniques.ToList(); // runs the algorithm and then the coloring techniques for each slice, in parallel. Parallel.ForEach(memorySlices, new ParallelOptions { MaxDegreeOfParallelism = maxParallelism }, memorySlice => { var span = memorySlice.Span; var start = memorySlice.Start; for (var i = 0; i < span.Length; i += 4) { //////////////////////////////////////////////////////////////////////////////////////////////////////// // first we need to calculate the pixel position based on the linear array index: // // x = index % width // y = index % height // // but take in account that the index is slice-based, so 0 is not really 0, but 0 + slice start. // so the formula now looks like: // // x = (index + start) % width // y = (index + start) / width // //////////////////////////////////////////////////////////////////////////////////////////////////////// var realIndex = i + start; var x = (int)(realIndex / 4.0f) % this.Width; var y = (int)(realIndex / 4.0f) / this.Width; // now we have the correct pixel coordinates, but we are working with a different coordinate system // in the complex space, dictated by the TopLeft and BottomRight corners, so we need to convert the // pixel coordinates to the fractal space. var complexNumber = this.ToFractalSpace(new Point(x, y)); // calculates the fractal algorithm for the complex number. var result = algorithm.Calculate(complexNumber, motion); // calculates all the colors based on the techniques. var colors = colorTechniques.Select(t => t.Colorize(result, color)).ToArray(); // calculates a final color combining all the different colors. var finalColor = combinationFunction(colors).ToSystemColor(); // sets the color coordinates in the slice. span[i] = finalColor.B; span[i + 1] = finalColor.G; span[i + 2] = finalColor.R; span[i + 3] = finalColor.A; } }); return(bitmapArray); }
public IAction CreateChangeAlgorithmAction(IFractalContext context, IFractalAlgorithm algorithm) { return(new ChangeParameterSelectionAction <IFractalAlgorithm>(context, c => c.CurrentAlgorithm, algorithm)); }