首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C中Mandelbrot集的缩放失真

C中Mandelbrot集的缩放失真
EN

Stack Overflow用户
提问于 2020-03-21 19:52:05
回答 2查看 897关注 0票数 1

我正在编写一个C程序来渲染Mandelbrot集,目前,我一直在尝试如何正确放大。

我希望变焦能够跟踪屏幕上的鼠标指针,这样分形就会放大到光标的位置。

我有一个窗口,定义为:

代码语言:javascript
复制
# define WIDTH 800
# define HEIGHT 600

我的Re_max, Re_min, Im_Max, Im_Min被定义并初始化如下:

代码语言:javascript
复制
man->re_max = 2.0;
man->re_min = -2.0;
man->im_max = 2.0;
man->im_min = -2.0;

插值值(稍后将详细介绍)定义并初始化如下:

代码语言:javascript
复制
pos->interp = 1.0;

为了将像素坐标映射到屏幕的中心,我使用了位置函数:

代码语言:javascript
复制
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是屏幕上指针的坐标:

代码语言:javascript
复制
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);
}

在注册鼠标滚轮滚动时,将调用此函数。实际缩放是通过以下功能实现的:

代码语言:javascript
复制
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);
    }
}

这就叫做:

代码语言:javascript
复制
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);
}

我有一个简单的插值函数来重新定义面积边界矩形:

代码语言:javascript
复制
double      interpolate(double start, double end, double interp)
{
    return (start + ((end - start) * interp));
}

所以问题是:

我的代码将分形呈现为- Mandelbrot集

但当我试图放大鼠标所描述的,而不是很好地“进入”,它只是扭曲了像,图像只是塌陷到自己,而不是实际上潜入分形。

我真的很感激在这方面的帮助,因为我已经坚持了一段时间了。

如果你也能解释一下你的解决方案背后的实际数学,我会非常高兴的!

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-03-24 15:21:50

在经历了相当多的头痛和大量的文件浪费在重新计算插值方法之后,我意识到,首先,我在屏幕上映射复杂数字的方式是不正确的。修改我的映射方法解决了我的问题,所以我将分享我所做的事情。

-------------------------------OLD WAY

我已经初始化了我的Re_max, Re_min, Im_Max, Im_Min值,它以以下方式定义了可见区域:

代码语言:javascript
复制
re_max = 2.0;
re_min = -2.0;
im_max = 2.0;
im_min = -2.0;

然后,我使用这种方法将屏幕上的坐标转换为用于计算分形的复数(注意,用于映射鼠标位置的缩放插值坐标和用于计算分形本身的坐标使用相同的方法):

代码语言:javascript
复制
Re = x / (WIDTH / (re_max - re_min)) + re_min;
Im = y / (HEIGHT / (im_max - re_min)) + im_min;

然而,这样我没有考虑屏幕比率,我忽略了这样一个事实(由于缺乏知识),屏幕上的y坐标是相反的(至少在我的程序中是这样)--负方向是向上的,正的是向下的。

这样,当我试图放大我的插值,自然,图像扭曲。

------------------------------CORRECT WAY

在定义集合的边界矩形时,应根据屏幕比率计算最大虚im_max)部分,以避免显示窗口不是正方形时的图像失真:

代码语言:javascript
复制
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*

代码语言:javascript
复制
re_factor = (re_max - re_min) / (WIDTH - 1);
im_factor = (im_max - im_min) / (HEIGHT - 1);

然后,我将像素坐标映射到计算中使用的复数的实部和虚部,如下所示:

代码语言:javascript
复制
c_re = re_min + x * re_factor;
c_im = im_max - y * im_factor;

在实现了这些更改之后,我终于能够顺利地缩放到鼠标位置,而没有任何失真或图像“跳跃”。

票数 2
EN

Stack Overflow用户

发布于 2020-03-23 14:38:03

如果我正确地理解了您,您想要指出鼠标位于图像的新中心,并将图像的比例尺更改为1.03倍。我会尝试这样的方法:

  • 您的位置()和mouse_move()函数保持不变。
  • 在zoom_control()中,只要改变设置插值的新值的方式,它就不应该是固定的常量,而应该基于其当前值。另外,将新的缩放因子传递给apply_zoom():
代码语言:javascript
复制
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);
    }
}
  • 修改应用变焦功能:
代码语言:javascript
复制
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;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60792570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档