public void LoadAsync(IFractal fractal, Bounds bounds) { BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += RunFractalLoad; IsLoading = true; worker.RunWorkerAsync(new AsyncLoadArgs { Bounds = bounds, Fractal = fractal, Renderer = renderer }); }
/// <summary>Precomputed values used during the rendering to speed up calculations.</summary> private void PrecomputeValues(IFractal fractal, Bounds bounds) { xIncrement = bounds.Width / width; yIncrement = bounds.Height / height; minBoundsX = bounds.X.MinValue; minBoundsY = bounds.Y.MinValue; }
/// <summary>Processes a fractal, computing its values, returning a RenderedFractal.</summary> public RenderedFractal Process(IFractal fractal, Bounds boundsToRender, Dimensions imageDimensions) { width = imageDimensions.Width; height = imageDimensions.Height; PrecomputeValues(fractal, boundsToRender); var buffer = new float[width * height]; Parallel.For(0, height, y => { Parallel.For(0, width, x => { SetPoint(buffer, fractal, x, y); }); }); return new RenderedFractal(buffer, fractal.MaxIterations, boundsToRender, fractal); }
/// <summary>Action to call when the mouse releases on the correct canvas.</summary> public void MouseUp(MouseEventArgs e, Canvas boundingBoxCanvas) { if (!isDrawing) return; isDrawing = false; if (boundingBox == null) return; boundingBoxCanvas.Children.Remove(boundingBox); var screenBounds = new Bounds( new Bound(Canvas.GetLeft(boundingBox), Canvas.GetLeft(boundingBox) + boundingBox.Width), new Bound(Canvas.GetTop(boundingBox), Canvas.GetTop(boundingBox) + boundingBox.Height)); if (BoxReleased != null) BoxReleased(screenBounds); boundingBox = null; }
/// <summary>Transforms the Bounds of the screen in to Bounds on the surface of the fractal.</summary> public Bounds GetFractalBounds(Bounds screenBounds) { var percentageBounds = new Bounds( new Bound( screenBounds.X.MinValue / ImageProvider.Dimensions.Width, screenBounds.X.MaxValue / ImageProvider.Dimensions.Width), new Bound( screenBounds.Y.MinValue / ImageProvider.Dimensions.Height, screenBounds.Y.MaxValue / ImageProvider.Dimensions.Height) ); var newBounds = new Bounds( new Bound( InternalLastRenderedBounds.X.MinValue + (InternalLastRenderedBounds.Width * percentageBounds.X.MinValue), InternalLastRenderedBounds.X.MinValue + (InternalLastRenderedBounds.Width * percentageBounds.X.MaxValue)), new Bound( InternalLastRenderedBounds.Y.MinValue + (InternalLastRenderedBounds.Height * percentageBounds.Y.MinValue), InternalLastRenderedBounds.Y.MinValue + (InternalLastRenderedBounds.Height * percentageBounds.Y.MaxValue))); return newBounds; }
/// <summary>Creates a new RenderedFractal with the data of the fractal.</summary> public RenderedFractal(float[] data, int maxIterations, Bounds bounds, IFractal fractal) : this(data, maxIterations) { Bounds = bounds; Fractal = fractal; }
/// <summary>Renders the fractal with the specified bounds, optionally ignoring pushing the bounds on to the history stack.</summary> private void RenderNew(Bounds bounds, bool ignoreHistory) { AsyncLoader.OnFinished += fractal => { if(!ignoreHistory) History.Push(fractal); SetImageDispatch(fractal); }; AsyncLoader.PostFinish += fractal => PostRender(fractal); AsyncLoader.LoadAsync(SelectedFractal, bounds); }
/// <summary>Renders the fractal with the specified bounds, pushing the render on to the history stack.</summary> private void RenderNew(Bounds bounds) { RenderNew(bounds, false); }
/// <summary>Loads a fractal to the specified bounds, converting from bounds obtained from screen units.</summary> public void LoadFractalFromScreenBounds(Bounds screenBounds) { var fractalBounds = renderer.GetFractalBounds(screenBounds); RenderNew(fractalBounds); }
/// <summary> /// Resizes the Bounds to match the aspect ratio of the iamge to be rendered. /// Prevents distorted images. /// </summary> private Bounds GetResizedBounds(Bounds areaToRender) { var realImageRatio = ImageProvider.Dimensions.Width / ImageProvider.Dimensions.Height; var desiredRatio = areaToRender.Width / areaToRender.Height; Bounds newBounds; if (realImageRatio < desiredRatio) { var additionalHeight = (ImageProvider.Dimensions.Height * areaToRender.Width) / ImageProvider.Dimensions.Width - areaToRender.Height; var amount = additionalHeight / 2; newBounds = new Bounds(areaToRender.X, new Bound(areaToRender.Y.MinValue - amount, areaToRender.Y.MaxValue + amount)); } else { var additionalWidth = (ImageProvider.Dimensions.Width * areaToRender.Height) / ImageProvider.Dimensions.Height - areaToRender.Width; var amount = additionalWidth / 2; newBounds = new Bounds(new Bound(areaToRender.X.MinValue - amount, areaToRender.X.MaxValue + amount), areaToRender.Y); } return newBounds; }
/// <summary> /// Gets a RenderedFractal by rendering the fractal with the area to render. /// /// The bounds will be scaled to match the ImageProvider dimensions. /// </summary> public RenderedFractal Render(IFractal fractal, Bounds areaToRender) { var bounds = GetResizedBounds(areaToRender); var renderedFractal = fractalProcessor.Process(fractal, bounds, ImageProvider.Dimensions); return Render(renderedFractal); }