在C#中设置Mandelbrot的点放大 - 除了鼠标移动外,它都有效

时间:2016-04-19 22:29:18

标签: c# zoom mandelbrot

只要鼠标在变焦开始后没有移动,我就可以对Mandelbrot设置进行缩放。我已经尝试过计算一​​个标准化的delta(新坐标 - 旧坐标)*(oldzoom),但是会发生什么情况,图像似乎跳到了一个新的位置。我以前见过这个问题。我在这里苦苦挣扎,因为我必须以某种方式将鼠标位置delta转换回Mandelbrot集的-2,2坐标空间。

这是我的代码。重要的是GetZoomPoint方法,然后是定义x0和y0的代码行。此外,我使用Range类将值从一个范围缩放到另一个范围。我使用deltaTrans(这就是我之前讨论过的事情,我用旧规模标准化鼠标增量)。

using OpenTK.Graphics.OpenGL;
using SpriteSheetMaker;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Fractal.Fractal
{
    public class Mandelbrot : BaseTexture
    {
        private static Transform GlobalTransform = SpriteSheetMaker.Global.Transform;
        private static Vector3 GlobalScale = GlobalTransform.Scale;
        private static Vector3 GlobalTrans = GlobalTransform.Translation;
        private static Vector3 LastWindowPoint = null;
        private static Vector3 ZoomFactor = Vector3.ONE * 1.2f;
        private static Vector3 Displacement = Vector3.ZERO;
        private static int WindowSize = 100;

        public static Vector3 GetZoomPoint()
        {


            var zP = OpenGLHelpers.LastZoomPoint.Clone();
            if (LastWindowPoint == null)
            {
                LastWindowPoint = zP.Clone();
            }
            var delta = zP - LastWindowPoint;
            var oldZoom = GlobalScale / ZoomFactor;
            var deltaTrans = delta.XY * oldZoom.XY;
            var factor = ZoomFactor.Clone();

            Range xR = new Range(0, WindowSize);
            Range yR = new Range(0, WindowSize);
            Range complexRange = new Range(-2, 2);

            // Calculate displacement of zooming position.
            var dx = (zP.X - Displacement.X) * (factor.X - 1f);
            var dy = (zP.Y - Displacement.Y) * (factor.Y - 1f);
            // Compensate for displacement.
            Displacement.X -= dx;
            Displacement.Y -= dy;

            zP -= Displacement;
            var x = complexRange.ScaleValue(zP.X, xR);
            var y = complexRange.ScaleValue(zP.Y, yR);

            var rtn = new Vector3(x, y);

            LastWindowPoint = zP.Clone();

            return rtn;
        }
        public static Mandelbrot Generate()
        {
            var size = new Size(WindowSize, WindowSize);
            var radius = new Size(size.Width / 2, size.Height / 2);

            Bitmap bmp = new Bitmap(size.Width, size.Height);
            LockBitmap.LockBitmapUnsafe lbm = new LockBitmap.LockBitmapUnsafe(bmp);
            lbm.LockBits();


            var pt = Mandelbrot.GetZoomPoint();
            Parallel.For(0, size.Width, i =>
            {
                //  float x0 = complexRangeX.ScaleValue(i, xRange);
                float x0 = ((i - radius.Width) / GlobalScale.X) + pt.X;

                Parallel.For(0, size.Height, j =>
                 {
                     // float y0 = complexRangeY.ScaleValue(j, yRange);
                     float y0 = ((j - radius.Height) / GlobalScale.Y) + pt.Y;
                     float value = 0f;
                     float x = 0.0f;
                     float y = 0.0f;
                     int iteration = 0;
                     int max_iteration = 100;
                     while (x * x + y * y <= 4.0 && iteration < max_iteration)
                     {
                         float xtemp = x * x - y * y + x0;
                         y = 2.0f * x * y + y0;
                         x = xtemp;
                         iteration += 1;
                         if (iteration == max_iteration)
                         {
                             value = 255;
                             break;
                         }
                         else
                         {
                             value = iteration * 50f % 255f;
                         }
                     }

                     int v = (int)value;
                     lbm.SetPixel(i, j, new ColorLibrary.HSL(v / 255f, 1.0, 0.5).ToDotNetColor());
                 });
            });
            lbm.UnlockBits();
            var tex = new BaseTextureImage(bmp);
            var rtn = new Mandelbrot(tex);
            return rtn;
        }

        public override void Draw()
        {
            base._draw();
        }
        private Mandelbrot(BaseTextureImage graphic)
        {
            var topLeft = new Vector3(0, 1);
            var bottomLeft = new Vector3(0, 0);
            var bottomRight = new Vector3(1, 0);
            var topRight = new Vector3(1, 1);
            this.Vertices = new List<Vector3>()
            {
                topLeft,bottomLeft,bottomRight,topRight
            };
            this.Size.X = WindowSize;
            this.Size.Y = WindowSize;
            this.Texture2D = graphic;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我重构了我的代码,并找到了解决这个问题的方法。一场2胜。好的,所以我找到了用C#编写的CodeProject解决方案,我很快就能适应我的项目了。我不确定为什么我在发布问题时没有意识到这一点,但我需要解决这个问题的是创建一个缩放的“窗口”,而不是考虑“点缩放”。是的,即使我试图直接缩放到一个点,这一点只是某种窗口的中心。

这是我的方法,它需要开始和结束的mousedown坐标(屏幕空间),并相应地转换mandelbrot设置窗口大小。

    public void ApplyZoom(double x0, double y0, double x1, double y1)
    {
        if (x1 == x0 && y0 == y1)
        {
            //This was just a click, no movement occurred
            return;
        }

        /*
            * XMin, YMin and XMax, YMax are the current extent of the set
            * mx0,my0 and mx1,my1 are the part we selected
            * do the math to draw the selected rectangle
            * */
        double scaleX, scaleY;

        scaleX = (XMax - XMin) / (float)BitmapSize;
        scaleY = (YMax - YMin) / (float)BitmapSize;
        XMax = (float)x1 * scaleX + XMin;
        YMax = (float)y1 * scaleY + YMin;
        XMin = (float)x0 * scaleX + XMin;
        YMin = (float)y0 * scaleY + YMin;

        this.Refresh(); // force mandelbrot to redraw

    }

基本上,我们正在计算mandelbrot窗口大小与我们绘制的屏幕大小之间的比率。然后,使用该比例,我们基本上将我们的mousedown坐标转换为mandelbrot设置坐标(x1 * scaleX等),并使用Min值作为轴心点来操纵当前的Min和Max坐标。

以下是我用作参考的CodeProject的链接:CodeProject link