我正在编写一个C程序来渲染Mandelbrot集,目前,我一直在尝试如何正确放大。
我希望变焦能够跟踪屏幕上的鼠标指针,这样分形就会放大到光标的位置。
我有一个窗口,定义为:
# define WIDTH 800
# define HEIGHT 600我的Re_max, Re_min, Im_Max, Im_Min被定义并初始化如下:
man->re_max = 2.0;
man->re_min = -2.0;
man->im_max = 2.0;
man->im_min = -2.0;插值值(稍后将详细介绍)定义并初始化如下:
pos->interp = 1.0;为了将像素坐标映射到屏幕的中心,我使用了位置函数:
void position(int x, int y, t_mandel *man)
{
double *s_x;
double *s_y;
s_x = &man->pos->shift_x;
s_y = &man->pos->shift_y;
man->c_re = (x / (WIDTH / (man->re_max - man->re_min)) + man->re_min) + *s_x;
man->c_im =(y / (HEIGHT / (man->im_max - man->re_min)) + man->im_min) + *s_y;
man->c_im *= 0.8;
}为了放大,我首先获取鼠标指针的坐标,然后使用这个函数将它们映射到由(Re_Max, Re_Min, Im_Max, Im_Min)定义的矩形给出的可见区域,其中x和y是屏幕上指针的坐标:
int mouse_move(int x, int y, void *p)
{
t_fract *fract;
t_mandel *man;
fract = (t_fract *)p;
man = fract->mandel;
fract->mouse->Re = x / (WIDTH / (man->re_max - man->re_min)) + man->re_min;
fract->mouse->Im = y / (HEIGHT / (man->im_max - man->re_min)) + man->im_min;
return (0);
}在注册鼠标滚轮滚动时,将调用此函数。实际缩放是通过以下功能实现的:
void zoom_control(int key, t_fract *fract)
{
double *interp;
interp = &fract->mandel->pos->interp;
if (key == 5) // zoom in
{
*interp = 1.0 / 1.03;
apply_zoom(fract->mandel, fract->mouse->Re, fract->mouse->Im, *interp);
}
else if (key == 4) // zoom out
{
*interp = 1.0 * 1.03;
apply_zoom(fract->mandel, fract->mouse->Re, fract->mouse->Im, *interp);
}
}这就叫做:
void apply_zoom(t_mandel *man, double m_re, double m_im, double interp)
{
man->re_min = interpolate(m_re, man->re_min, interp);
man->im_min = interpolate(m_im, man->im_min, interp);
man->re_max = interpolate(m_re, man->re_max, interp);
man->im_max = interpolate(m_im, man->im_max, interp);
}我有一个简单的插值函数来重新定义面积边界矩形:
double interpolate(double start, double end, double interp)
{
return (start + ((end - start) * interp));
}所以问题是:
我的代码将分形呈现为- Mandelbrot集。
但当我试图放大鼠标所描述的,而不是很好地“进入”,它只是扭曲了像这,图像只是塌陷到自己,而不是实际上潜入分形。
我真的很感激在这方面的帮助,因为我已经坚持了一段时间了。
如果你也能解释一下你的解决方案背后的实际数学,我会非常高兴的!
谢谢!
发布于 2020-03-24 15:21:50
在经历了相当多的头痛和大量的文件浪费在重新计算插值方法之后,我意识到,首先,我在屏幕上映射复杂数字的方式是不正确的。修改我的映射方法解决了我的问题,所以我将分享我所做的事情。
-------------------------------OLD WAY
我已经初始化了我的Re_max, Re_min, Im_Max, Im_Min值,它以以下方式定义了可见区域:
re_max = 2.0;
re_min = -2.0;
im_max = 2.0;
im_min = -2.0;然后,我使用这种方法将屏幕上的坐标转换为用于计算分形的复数(注意,用于映射鼠标位置的缩放插值坐标和用于计算分形本身的坐标使用相同的方法):
Re = x / (WIDTH / (re_max - re_min)) + re_min;
Im = y / (HEIGHT / (im_max - re_min)) + im_min;然而,这样我没有考虑屏幕比率,我忽略了这样一个事实(由于缺乏知识),屏幕上的y坐标是相反的(至少在我的程序中是这样)--负方向是向上的,正的是向下的。
这样,当我试图放大我的插值,自然,图像扭曲。
------------------------------CORRECT WAY
在定义集合的边界矩形时,应根据屏幕比率计算最大虚im_max)部分,以避免显示窗口不是正方形时的图像失真:
re_max = 2.0;
re_min = -2.0;
im_min = -2.0;
im_max = im_min + (re_max - re_min) * HEIGHT / WIDTH;为了将屏幕上的坐标映射到复数,我首先找到了“坐标与数字的比率”,它等于*rectangle length / screen width*。
re_factor = (re_max - re_min) / (WIDTH - 1);
im_factor = (im_max - im_min) / (HEIGHT - 1);然后,我将像素坐标映射到计算中使用的复数的实部和虚部,如下所示:
c_re = re_min + x * re_factor;
c_im = im_max - y * im_factor;在实现了这些更改之后,我终于能够顺利地缩放到鼠标位置,而没有任何失真或图像“跳跃”。
发布于 2020-03-23 14:38:03
如果我正确地理解了您,您想要指出鼠标位于图像的新中心,并将图像的比例尺更改为1.03倍。我会尝试这样的方法:
void zoom_control(int key, t_fract *fract)
{
double *interp;
interp = &fract->mandel->pos->interp;
double zoom_factor = 1.03;
if (key == 5) // zoom in
{
*interp /= zoom_factor;
apply_zoom(fract->mandel, fract->mouse->Re, fract->mouse->Im, 1.0 / zoom_factor);
}
else if (key == 4) // zoom out
{
*interp *= zoom_factor;
apply_zoom(fract->mandel, fract->mouse->Re, fract->mouse->Im, zoom_factor);
}
}void apply_zoom(t_mandel *man, double m_re, double m_im, double zoom_factor)
{
// Calculate the new ranges along the real and imaginary axes.
// They are equal to the current ranges multiplied by the zoom_factor.
double re_range = (man->re_max - man->re_min) * zoom_factor;
double im_range = (man->im_max - man->im_min) * zoom_factor;
// Set the new min/max values for real and imaginary axes with the center at
// mouse coordinates m_re and m_im.
man->re_min = m_re - re_range / 2;
man->re_max = m_re + re_range / 2;
man->im_min = m_im - im_range / 2;
man->im_max = m_im + im_range / 2;
}https://stackoverflow.com/questions/60792570
复制相似问题