我正在尝试找到一种方法来放大我的 Mandelbrot 设置。我有它,所以当我单击它时,它会稍微放大,但它不会相应地移动 Mandelbrot。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Numerics;
namespace Project_V2
{
public partial class FractalGen : Form
{
public double zoom = 2.4;
public FractalGen()
{
InitializeComponent();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
zoom -= 0.3;
Mandelbrot();
}
private void button1_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
Mandelbrot();
}
private void timer1_Tick(object sender, EventArgs e)
{
}
private void Mandelbrot()
{
Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
DateTime StartT = DateTime.Now;
for (int x = 0; x < pictureBox1.Width; x++)
{
for (int y = 0; y < pictureBox1.Height; y++)
{
double a = (double)(x - (pictureBox1.Width / 1.25)) / (double)(pictureBox1.Width / zoom);
double b = (double)(y - (pictureBox1.Height / 2)) / (double)(pictureBox1.Height / zoom);
Complex C = new Complex(a, b);
Complex Z = new Complex(0, 0);
int u = 0;
do
{
u++;
Z = Z * Z;
Z = Z + C;
double Mag = Complex.Abs(Z);
if (Mag > 2.0) break;
} while (u < 255);
Color rgbInside = Color.FromArgb(0, 0, 0);
Color rgbOutside = Color.FromArgb(u >= 127 ? 255 : 2 * u, u >= 127 ? (u - 127) : 0, 0);
bm.SetPixel(x, y, u < 255 ? rgbOutside : rgbInside);
}
}
pictureBox1.Image = bm;
DateTime EndT = DateTime.Now;
string Time = Convert.ToString((EndT - StartT).TotalSeconds);
textBox1.Text = "Time Taken: " + Time + " Seconds";
}
private void button1_Click_1(object sender, EventArgs e)
{
zoom = 2.4;
Mandelbrot();
}
private void button2_Click(object sender, EventArgs e)
{
saveFileDialog1.ShowDialog();
}
private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{
string name = saveFileDialog1.FileName;
pictureBox1.Image.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Png);
}
}
}
当前代码将图片框的宽度和高度除以一个值,但我想要它,以便它放大我单击的位置。 如何根据我点击的位置缩放图片框?
了解已经向您提供了哪些指导将会很有帮助。我从此评论推断,您可能提出了一个现有问题,然后将其删除,其中讨论了此问题。如果不知道已经提供了哪些帮助以及您无法理解的具体内容,就很难知道如何最好地提出新答案。
也就是说,要实现您正在寻找的行为,您必须解决两个基本问题:
Click
事件,该事件仅向您的代码报告单击了控件,而不报告单击了 where。zoom
变量。要解决#1,您需要订阅
MouseClick
事件。这会将 MouseEventArgs
对象传递给您的处理程序,该处理程序具有 Location
属性,指示实际单击的控件客户区域内的点(即报告的坐标相对于控件左上角的原点) ).
要解决#2,您需要向类中添加一些变量来跟踪要绘制的相对位置。有很多方法可以做到这一点,但是按照当前将当前“缩放”系数表示为渲染区域的宽度和高度的惯例,跟踪正在渲染的空间的中心似乎是有意义的,即鼠标单击的位置,就绘制的复平面上的位置而言。
我强烈反对在执行长时间运行的任务时锁定 UI 的程序。因此,在修改代码示例的过程中,我对其进行了修改,以便它可以在工作线程中渲染图像,并通过在我添加到表单中的
Label
上提供状态消息来报告渲染进度。 (这涉及使您的 Mandelbrot()
方法成为 async
方法……我继续在调用它时使用 await
来抑制编译器警告,但当然在这种情况下,并不严格需要 await
。)
我做了没有做的一件事是对代码添加进一步的优化。这些往往会混淆与您的问题直接相关的更改。您可以对代码执行许多操作来帮助提高性能,方法是删除冗余计算或使用数学关系来执行计算,其成本比 Mandelbrot 算法的直译更便宜。
互联网上有很多关于如何渲染 Mandelbrot 图像的信息,因此,一旦您掌握了基本想法,您就可以四处寻找此类建议。此外,目前每个像素只有 255 次迭代和相对较小的位图,性能并不是一个重要的考虑因素。
这是我想出的代码版本:
public partial class Form1 : Form
{
double zoom = 2.4;
double centerX = -0.72, centerY = 0;
public Form1()
{
InitializeComponent();
}
private async void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
double minX = centerX - zoom / 2, minY = centerY - zoom / 2;
centerX = minX + (double)e.Location.X / pictureBox1.Width * zoom;
centerY = minY + (double)e.Location.Y / pictureBox1.Height * zoom;
zoom -= 0.3;
await Mandelbrot();
}
private async void Form1_Load(object sender, EventArgs e)
{
await Mandelbrot();
}
private async Task Mandelbrot()
{
IProgress<double> progress = new Progress<double>(x => label1.Text = $"{x * 100:0}% done");
DateTime StartT = DateTime.UtcNow;
pictureBox1.Image = await Task.Run(() => _GenerateBitmap(progress));
DateTime EndT = DateTime.UtcNow;
string Time = Convert.ToString((EndT - StartT).TotalSeconds);
textBox1.Text = "Time Taken: " + Time + " Seconds";
}
private Bitmap _GenerateBitmap(IProgress<double> progress)
{
Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
double minX = centerX - zoom / 2, minY = centerY - zoom / 2;
for (int x = 0; x < pictureBox1.Width; x++)
{
for (int y = 0; y < pictureBox1.Height; y++)
{
double a = minX + (double)x / pictureBox1.Width * zoom;
double b = minY + (double)y / pictureBox1.Height * zoom;
Complex C = new Complex(a, b);
Complex Z = new Complex(0, 0);
int u = 0;
do
{
u++;
Z = Z * Z;
Z = Z + C;
double Mag = Complex.Abs(Z);
if (Mag > 2.0) break;
} while (u < 255);
Color rgbInside = Color.FromArgb(0, 0, 0);
Color rgbOutside = Color.FromArgb(u >= 127 ? 255 : 2 * u, u >= 127 ? (u - 127) : 0, 0);
bm.SetPixel(x, y, u < 255 ? rgbOutside : rgbInside);
}
progress.Report((double)x / pictureBox1.Width);
}
return bm;
}
private async void button1_Click_1(object sender, EventArgs e)
{
zoom = 2.4;
await Mandelbrot();
}
}
查看https://github.com/alexsokolek2/mandelbrot。特别是,请参见 mandelbrot.cpp/case WM_MOUSEWHEEL。当鼠标滚轮旋转时,此代码会放大和缩小当前鼠标位置。您应该能够迁移代码,以便您可以通过单击来放大或缩小。 (我的代码以左键单击为中心。有关详细信息,请参阅案例 WM_LBUTTONCLICK。)请注意,WM_MOUSEWHEEL 以屏幕坐标报告,您需要使用 ScreenToClient() 函数将它们转换为客户端坐标。