我正在编写一个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 set
但是,当我尝试按照鼠标的描述进行放大时,它并没有像“ C0”那样很好地扭曲,它只是像塌陷在其自身上,而不是实际进入分形中。
我很高兴能对此提供帮助,因为我已经坚持了一段时间。
如果您也可以解释解决方案背后的实际数学,我将非常高兴!
谢谢!
如果我对您的理解正确,您希望将鼠标位于图像的新中心,并以1.03的倍数更改图像的比例。我会尝试类似的东西:
您的position()和mouse_move()函数保持不变。
在zoom_control()中只是更改了设置新插值值的方式,它不应为固定常数,而应基于其当前值。另外,将新的缩放因子传递给apply_zoom():
this
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;
}
值,该值通过以下方式定义了可见区域:
Re_max, Re_min, Im_Max, Im_Min
然后,我使用此方法将屏幕上的坐标转换为用于计算分形的复数(请注意,用于映射鼠标位置以进行缩放插值的坐标和用于计算分形本身的坐标使用相同的方法):
re_max = 2.0;
re_min = -2.0;
im_max = 2.0;
im_min = -2.0;
然而,这样我就没有考虑屏幕比例,而忽略了由于缺乏知识而导致屏幕上的[y]坐标为inverse]的事实。 (至少在我的程序中)-负方向是up,正方向是down。这样,当我尝试通过插值放大时,图像自然会失真。
------------------------------
正确方式
------------ -----------------------当定义集合的边界矩形时,应根据屏幕比例计算maximum imaginary im_max)
的部分,以避免在显示窗口不是正方形时图像失真。Re = x / (WIDTH / (re_max - re_min)) + re_min;
Im = y / (HEIGHT / (im_max - re_min)) + im_min;
[将屏幕上的坐标映射到复数,我首先发现“坐标数比*,等于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*
然后,我将像素坐标映射到计算中使用的复数的和imaginary部分,如下所示:real
re_factor = (re_max - re_min) / (WIDTH - 1);
im_factor = (im_max - im_min) / (HEIGHT - 1);
完成这些更改之后,我终于能够平稳地放大到鼠标位置,而没有任何失真或图像“跳动”。