/************************************************************************** * ***************************************************************************/ private void Zoom(Rectangle window) { // don't bother zooming if the size is too small. if (window.Height < 10 || window.Width < 10) { return; } // stretch zoom using (Bitmap bitmap = new Bitmap(myPictureBox.Width, myPictureBox.Height, PixelFormat.Format32bppPArgb)) using (Graphics g = Graphics.FromImage((Image)bitmap)) { g.DrawImage(_canvas, myPictureBox.ClientRectangle, window, GraphicsUnit.Pixel); } myPictureBox.Invalidate(true); // HORRIBLE !! // Need to use async/await Application.DoEvents(); // calculate new window and render aComplexNumber tlPoint = new aComplexNumber(); aComplexNumber brPoint = new aComplexNumber(); TransformCoord(window.X, window.Y, ref tlPoint); TransformCoord(window.Right, window.Bottom, ref brPoint); _complexWindow.MinX = tlPoint.Real; _complexWindow.MaxX = brPoint.Real; _complexWindow.MinY = brPoint.Imaginary; _complexWindow.MaxY = tlPoint.Imaginary; Render(); }
/************************************************************************** * Test the given coordinate to see if it is inside the Mandelbrot set * * Returns 0 if it is part of the set. * If not, returns the number of tries reached. * ***************************************************************************/ private int TestForMandelbrotSetAsync(int x, int y) { int iterationsTaken = 0; aComplexNumber Z = new aComplexNumber(); aComplexNumber C = new aComplexNumber(); // Set initial value of Zn to 0+0i Z.Real = 0; Z.Imaginary = 0; // get the imaginary coordinate that is represented by our current position TransformCoord(x, y, ref C); // To test for divergence, we perform an iterative loop of the form: // Zn+1 = Zn^2 + C // // If the magnitude of Z goes above 2, then it is within the Mandelbrot set. double ZrSq = Z.Real * Z.Real; double ZiSq = Z.Imaginary * Z.Imaginary; for (iterationsTaken = 0; iterationsTaken < _complexWindow.MaxThreshold; iterationsTaken++) { /*********************************** * aComplexNumber Zn = Z.Squared() + C; * if (Zn.IsDivergent()) * break; * Z = Zn; ***********************************/ // optimisation of above code // Test for divergence // No need to do the square root for a little perf. increase. if (ZrSq + ZiSq > 4.0) { break; } Z.Imaginary = Z.Real * Z.Imaginary; Z.Imaginary += Z.Imaginary; Z.Imaginary += C.Imaginary; Z.Real = ZrSq - ZiSq + C.Real; ZrSq = Z.Real * Z.Real; ZiSq = Z.Imaginary * Z.Imaginary; } if (iterationsTaken >= _complexWindow.MaxThreshold) { return(0); } // Not inside the Mandelbrot set return(iterationsTaken); }
/************************************************************************** * Handler for the mouse button up event * * Use this event to update our image if we have been zooming or panning. ***************************************************************************/ private void PictureBox_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (_isZooming) { _isZooming = false; Point endZoomPoint = new Point(e.X, e.Y); // Call zoom function Rectangle window = new Rectangle( Math.Min(_startPoint.X, endZoomPoint.X), Math.Min(_startPoint.Y, endZoomPoint.Y), Math.Abs(_startPoint.X - endZoomPoint.X), Math.Abs(_startPoint.Y - endZoomPoint.Y)); Zoom(window); } else if (_isPanning) { _isPanning = false; Point endPoint = new Point(e.X, e.Y); _panninggrapics?.Dispose(); _panninggrapics = null; // calculate distance moved on each axis. aComplexNumber start = new aComplexNumber(); aComplexNumber end = new aComplexNumber(); TransformCoord(_startPoint.X, _startPoint.Y, ref start); TransformCoord(endPoint.X, endPoint.Y, ref end); double deltaX = end.Real - start.Real; double deltaY = end.Imaginary - start.Imaginary; _complexWindow.MinX -= deltaX; _complexWindow.MaxX -= deltaX; _complexWindow.MinY -= deltaY; _complexWindow.MaxY -= deltaY; using (Bitmap tempbitmap = (Bitmap)_canvas.Clone()) using (Graphics g = Graphics.FromImage(_canvas)) { GraphicsUnit gu = GraphicsUnit.Pixel; g.FillRectangle(new SolidBrush(Color.SeaGreen), _canvas.GetBounds(ref gu)); g.DrawImage(tempbitmap, (endPoint.X - _startPoint.X), (endPoint.Y - _startPoint.Y)); } Render(); } } }
/************************************************************************** * Handles the mouse movement event * * This handler has a few tasks. * . Handles image movement, if we are panning * . Updates zoom coordinates, if we are zooming in. * ***************************************************************************/ private void PictureBox_MouseMove(object sender, MouseEventArgs e) { // If we are still rendering our image, then do no continue if (_isRendering) { return; } if (_isZooming) { Point endZoomPoint = new Point(e.X, e.Y); _ZoomWindow = new Rectangle( Math.Min(_startPoint.X, endZoomPoint.X), Math.Min(_startPoint.Y, endZoomPoint.Y), Math.Abs(_startPoint.X - endZoomPoint.X), Math.Abs(_startPoint.Y - endZoomPoint.Y)); myPictureBox.Invalidate(); return; } // we are panning our image, so move to the new position if (_isPanning) { Point endPoint = new Point(e.X, e.Y); _panninggrapics.FillRectangle(new SolidBrush(Color.DimGray), myPictureBox.ClientRectangle); _panninggrapics.DrawImage(_canvas, (endPoint.X - _startPoint.X), (endPoint.Y - _startPoint.Y)); return; } aComplexNumber C = new aComplexNumber(); TransformCoord(e.X, e.Y, ref C); // output the coordinates to the screen statusLabel.Text = $"x: {C.Real:0.####} y:{C.Imaginary:0.####}"; }
public aComplexNumber(aComplexNumber c) { _real = c._real; _imaginary = c._imaginary; }
/************************************************************************** * Maps the given screen position to the complex plane being rendered ***************************************************************************/ private void TransformCoord(int x, int y, ref aComplexNumber complexPoint) { complexPoint.Real = ((x * (_complexWindow.MaxX - _complexWindow.MinX)) / myPictureBox.Width) + _complexWindow.MinX; complexPoint.Imaginary = (((myPictureBox.Height - y) * (_complexWindow.MaxY - _complexWindow.MinY)) / myPictureBox.Height) + _complexWindow.MinY; }
/************************************************************************** * Transform the given screen coordinate to the represented complex number ***************************************************************************/ private void TransformCoord(Point screenPoint, ref aComplexNumber complexPoint) { TransformCoord(screenPoint.X, screenPoint.Y, ref complexPoint); }