Exemplo n.º 1
0
        /// <summary>Starts calculating the mandelnumbers for the given area of the mandelbrot set.</summary>
        /// <param name="args">The area to calculate</param>
        public void Calculate(MandelAreaArgs args)
        {
            lock(locker)
            {
                // Abort any old workers
                Abort();

                // Make sure the x axis lies in the middel of a pixel
                args.CenterOnXAxis();

                // Create a new worker
                worker = new Worker(args);
                worker.OnWorkFinished = WorkFinished;

                // Determine which indexes should be calculated and which can be determined using the symmetry of the mandelbrot set
                int startIndex = 0;
                int endIndex = args.CalcArea.Width * args.CalcArea.Height;
                if(args.CalcAreaTop() > 0.0 && args.CalcAreaBottom() < 0.0)
                {
                    if(args.CalcAreaTop() >= -args.CalcAreaBottom())
                    {
                        // `endIndex` = `rows of pixels above the x-axis including the x-axis` * `width in pixels`
                        endIndex = (int) Math.Min(endIndex, Math.Round((args.CalcAreaTop() / args.Scale + 1) * args.CalcArea.Width));
                    }
                    else
                    {
                        // `startIndex` = `rows of pixels above the x-axis excluding the x-axis` * `width in pixels`
                        startIndex = (int) Math.Round((args.CalcAreaTop() / args.Scale) * args.CalcArea.Width);
                    }
                }

                // Queue the work items
                workFinished = new Dictionary<int, bool>((int) Math.Ceiling(((double) endIndex - startIndex) / WORK_PER_THREAD));
                for(int i = startIndex; i < endIndex; i += WORK_PER_THREAD)
                {
                    workFinished[i] = false;
                    ThreadPool.QueueUserWorkItem(new WaitCallback(worker.Work), new Worker.WorkerArgs(i, Math.Min(i + WORK_PER_THREAD, endIndex)));
                }
            }
        }
        public MandelDisplay()
        {
            // Initialize the control
            InitializeComponent();

            // Initialiaze some fields
            currArea = new MandelAreaArgs();
            calcedArea = new MandelAreaArgs();
            mandelNumbers = null;
            img = null;
            calculating = false;
            mandelNumberToColor = defaultMandelNumberToColor;

            // Create and attach the mandelbrot calculator
            mandelbrot = new Mandelbrot();
            mandelbrot.OnCalculationDone = onMandelbrotDoneHandler;
            this.Controls.Add(mandelbrot);

            // Connect the event handlers
            this.Paint += this.paint;

            // Some properties of the control
            this.ResizeRedraw = true;
        }
Exemplo n.º 3
0
 /// <summary>Constructs a Worker to calculate the mandelnumbers for a certain area</summary>
 /// <param name="args">The area that is to be calculated</param>
 public Worker(MandelAreaArgs args)
 {
     mandelNumbers = new int[args.CalcArea.Width * args.CalcArea.Height];
     mandelAreaArgs = args;
 }
Exemplo n.º 4
0
 /// <summary>Calls the OnCalculationDoneHandler</summary>
 /// <param name="args">The area for which the calculation was done that is to be passed to the OnCalculationDoneHandler</param>
 /// <param name="mandelNumbers">The array of mandelnumbers that is to passed to the OnCalculationDoneHandler</param>
 private void CallOnCalculationDone(MandelAreaArgs args, int[] mandelNumbers)
 {
     if(onCalculationDoneHandler != null)
         BeginInvoke(onCalculationDoneHandler, new object[] { args, mandelNumbers });
 }
        /// <summary>Recalculates the mandelbrot for the current size and area</summary>
        public void Recalc()
        {
            // Start the new calculation
            if(mandelNumbers != null && currArea.Scale == calcedArea.Scale && currArea.MaxIterations == calcedArea.MaxIterations)
            {
                if(currArea.CenterX == calcedArea.CenterX && currArea.CenterY == calcedArea.CenterY && currArea.PxWidth == calcedArea.PxWidth && currArea.PxHeight == calcedArea.PxHeight)
                    renderBitmap();
                else
                {
                    // Calculate the translation
                    int transX = (int) Math.Round((calcedArea.CenterX - currArea.CenterX) / calcedArea.Scale);
                    int transY = (int) Math.Round((currArea.CenterY - calcedArea.CenterY) / calcedArea.Scale);

                    // Check if the already calculated area and the area that is to be calculated overlap
                    if(calcedArea.CalcArea.X + transX < currArea.PxWidth && calcedArea.CalcArea.Y + transY < currArea.PxHeight &&
                       calcedArea.CalcArea.X + transX + calcedArea.CalcArea.Width > 0 && calcedArea.CalcArea.Y + transY + calcedArea.CalcArea.Height > 0)
                    {
                        // Calculate the overlapping area (in the pixel coordinates of currArea)
                        Rectangle overlap = new Rectangle(calcedArea.CalcArea.X + transX, calcedArea.CalcArea.Y + transY, calcedArea.CalcArea.Width, calcedArea.CalcArea.Height);
                        overlap.Intersect(new Rectangle(0, 0, currArea.PxWidth, currArea.PxHeight));

                        // Create a new array of mandelnumbers
                        int[] tmpMandelNumbers = new int[overlap.Width * overlap.Height];
                        for(int x = 0; x < overlap.Width; ++x)
                            for(int y = 0; y < overlap.Height; ++y)
                                tmpMandelNumbers[x + y * overlap.Width] = mandelNumbers[x + overlap.X - transX + (y + overlap.Y - transY) * calcedArea.CalcArea.Width];

                        // Set the calcedArea and mandelNumber to the new values overlapping values
                        calcedArea = currArea;
                        calcedArea.CalcArea = overlap;
                        mandelNumbers = tmpMandelNumbers;

                        // Start filling the gaps
                        calcPart();

                        // Create a new bitmap of the right size and copy the old one to it
                        Bitmap newImg = new Bitmap(calcedArea.PxWidth, calcedArea.PxHeight);
                        Graphics.FromImage(newImg).FillRectangle(Brushes.White, 0, 0, calcedArea.PxWidth, calcedArea.PxHeight);
                        Graphics.FromImage(newImg).DrawImage(img, transX, transY);
                        img = newImg;
                    }
                    else
                    {
                        // Just start a regular calculation if they don't overlap
                        expectWholeArea = true;
                        mandelbrot.Calculate(currArea);
                        calculating = true;
                    }
                }
            }
            else
            {
                expectWholeArea = true;
                mandelbrot.Calculate(currArea);
                calculating = true;
            }

            // Redraw the screen
            Invalidate();
        }
        /// <summary>Handler for when `mandelbrot` is done calculating</summary>
        private void onMandelbrotDoneHandler(MandelAreaArgs args, int[] result)
        {
            if(expectWholeArea)
            {
                // Remember the area for which the calculation has been done
                calcedArea = args;
                mandelNumbers = result;

                // Recalculate the color map if the maximum amount of iterations has changed
                if(colorMap.Length != calcedArea.MaxIterations + 1)
                {
                    colorMap = new Color[calcedArea.MaxIterations + 1];
                    for(int i = 0; i <= calcedArea.MaxIterations; ++i)
                        colorMap[i] = mandelNumberToColor(i, calcedArea.MaxIterations);
                }

                // We're done calculating
                calculating = false;

                // Render the bitmap
                renderBitmap();
            }
            else
            {
                // Calculate the new calcedArea.CalcArea
                Rectangle newCalcArea = new Rectangle(Math.Min(calcedArea.CalcArea.X, args.CalcArea.X),
                                                     Math.Min(calcedArea.CalcArea.Y, args.CalcArea.Y),
                                                     1, 1);
                newCalcArea.Width = Math.Max(calcedArea.CalcArea.Right, args.CalcArea.Right) - newCalcArea.X;
                newCalcArea.Height = Math.Max(calcedArea.CalcArea.Bottom, args.CalcArea.Bottom) - newCalcArea.Y;

                // Copy the new mandelnumbers together with the current mandelnumbers to a new array
                int[] tmpMandelNumbers = new int[newCalcArea.Width * newCalcArea.Height];
                for(int x = 0; x < newCalcArea.Width; ++x)
                {
                    for(int y = 0; y < newCalcArea.Height; ++y)
                    {
                        if(args.CalcArea.Contains(newCalcArea.X + x, newCalcArea.Y + y))
                            tmpMandelNumbers[x + y * newCalcArea.Width] = result[newCalcArea.X + x - args.CalcArea.X + (newCalcArea.Y + y - args.CalcArea.Y) * args.CalcArea.Width];
                        else
                            tmpMandelNumbers[x + y * newCalcArea.Width] = mandelNumbers[newCalcArea.X + x - calcedArea.CalcArea.X + (newCalcArea.Y + y - calcedArea.CalcArea.Y) * calcedArea.CalcArea.Width];
                    }
                }

                // Store the new result
                mandelNumbers = tmpMandelNumbers;
                calcedArea.CalcArea = newCalcArea;

                // Fill the next gap, or render the bitmap (if we've filled all gaps)
                if(!calcPart())
                    renderBitmap();
            }
        }
 /// <summary>Sets the area of the mandelbrot that is to be shown (note that the CalcArea property is ignored)</summary>
 /// <param name="mea">The area of the mandelbrot that is to be shown</param>
 public void SetArea(MandelAreaArgs mea)
 {
     currArea = mea;
     currArea.CalcArea = new Rectangle(0, 0, currArea.PxWidth, currArea.PxHeight);
     currArea.CenterOnXAxis();
     currArea.CenterOnYAxis();
     Invalidate();
 }
Exemplo n.º 8
0
 void OnMandelbrotDoneHandler(MandelAreaArgs args, int[] result)
 {
     deltaTicks = Environment.TickCount - startTicks;
     mandelNumbers = result;
     lastCalcW = args.PxWidth;
     lastCalcH = args.PxHeight;
     Invalidate();
 }