线性随机IFS迭代法(C++)

IFS是迭代函数系统(Iterated Function System)的缩写. 它是一种数学工具, 常用于计算机图形学中生成分形图像. 在IFS中, 一组迭代函数被定义, 并且从一个简单的初始值开始, 通过重复应用这些函数, 可以生成复杂的结构. 这些迭代函数通常具有某种相似性或变换性质, 例如平移, 缩放, 旋转等. 在计算机图形学中, IFS用于创建分形图像, 其中每个像素或像素块被迭代函数处理, 以生成最终的图像. 这种方法可以生成具有自然现象(如山脉, 云朵, 树等)的复杂结构的图像. 此外, 随机IFS是一种特殊的IFS, 其中迭代函数和初始值都是随机选择的. 这种方法通常用于创建抽象艺术和计算机生成的艺术作品.

在本文仅在平面上考虑线性随机IFS迭代.

算法描述

在二维平面上, 我们有如下的仿射变换:
( x ′ y ′ ) = ( a b c d ) ( x y ) + ( e f ) \begin{pmatrix} x^\prime\\y^\prime \end{pmatrix} =\begin{pmatrix} a&b\\c&d \end{pmatrix} \begin{pmatrix} x\\y \end{pmatrix}+ \begin{pmatrix} e\\f \end{pmatrix} (xy)=(acbd)(xy)+(ef)

对于一个比较复杂的图形, 可能需要多个不同的仿射变换来实现, 仿射变换族 { ω n } \{\omega_n\} {ωn}控制着图形的结构和形状, 由于仿射变换的形式是相同的, 所以不同的形状取决于仿射变换的系数. 另外, 仿射变换族 { ω n } \{\omega_n\} {ωn}中, 每一个仿射变换被调用的概率不一定是等同的, 也就是说, 落入图形各部分中点的数目不一定相同, 这就需要引进一个新的量, 即仿射变换 ω \omega ω被调用的概率 P P P. 从而, 6个仿射变换系数 { a , b , c , d , e , f } \{a,b,c,d,e,f\} {a,b,c,d,e,f}和一个概率 P P P便组成了线性随机IFS迭代最关键的部分——IFS码.

给定一个IFS码, 我们便可以进行多次迭代, 最终生成所需的图形.

线性随机IFS迭代法可描述如下:

  • 输入:IFS码 A \bm A A,迭代次数 n n n,迭代初值 x 0 \bm x_0 x0
  • 输出:迭代路径 p p p
  1. 初始化 P P P A A A 的最后1列逐元素累加
  2. 对于 i i i 1 1 1 n n n 进行以下步骤:
    • 生成 [ 0 , 1 ) [0,1) [0,1) 均匀分布的随机数 r r r
    • P P P 中找到第一个大于 r r r 的下标 d d d
    • 利用 A A A 的第 d d d 行进行仿射变换并加到 p p p
  3. 返回 p p p

算法实现

首先预处理如下:

#include <armadillo>
#include <stdio.h>
#include <random>
#include <ctime>
using namespace arma;
using namespace std;

再实现线性随机IFS迭代:

/*
 * 线性随机IFS迭代
 * ifs : IFS码
 * n   : 迭代次数
 * x0  : 迭代初值
 * path: 迭代过程保存路径
 * e   : 实数比较精度
 *
 * 返回(bool):
 *  true : 迭代失败
 *  false: 迭代成功
 */
bool IFS_iteration(const mat &ifs, unsigned n, const char *path, vec x0 = randu(2), const double &e = 1e-6)
{
    if (ifs.n_cols != 7 || x0.n_elem != 2)
        return true;
    if (!n)
        return true;
    vec p = cumsum(ifs.col(6));
    if (abs(p.at(p.n_elem - 1) - 1.) > e)
        return true;
    FILE *file;
    if (fopen_s(&file, path, "w"))
        return true;
    fprintf(file, "x,y\n%f,%f", x0.at(0), x0.at(1));
    static default_random_engine engine(time(nullptr));
    static uniform_real_distribution<double> distribution;
    do
    {
        double d(distribution(engine));
        unsigned i(0);
        while (p.at(i) <= d)
            if (++i == p.n_elem)
            {
                --i;
                break;
            }
        d = ifs.at(i, 0) * x0.at(0) + ifs.at(i, 1) * x0.at(1) + ifs.at(i, 4);
        x0.at(1) = ifs.at(i, 2) * x0.at(0) + ifs.at(i, 3) * x0.at(1) + ifs.at(i, 5);
        x0.at(0) = d;
        fprintf(file, "\n%f,%f", x0.at(0), x0.at(1));
    } while (--n);
    fclose(file);
    return false;
}

实例分析

已知某树木的IFS码如下所示:
A = ( 0.06 0 0 0.6 0 0 0.1 0.04 0 0 − 0.5 0 1 0.1 0.46 0.32 − 0.34 0.38 0 0.6 0.1 0.48 − 0.15 0.17 0.42 0 1 0.23 0.43 0.37 − 0.26 0.48 0 1 0.23 0.42 − 0.36 0.35 0.31 0 0.8 0.24 ) A=\begin{pmatrix} 0.06&0&0&0.6&0&0&0.1\\ 0.04&0&0&-0.5&0&1&0.1\\ 0.46&0.32&-0.34&0.38&0&0.6&0.1\\ 0.48&-0.15&0.17&0.42&0&1&0.23\\ 0.43&0.37&-0.26&0.48&0&1&0.23\\ 0.42&-0.36&0.35&0.31&0&0.8&0.24 \end{pmatrix} A= 0.060.040.460.480.430.42000.320.150.370.36000.340.170.260.350.60.50.380.420.480.31000000010.6110.80.10.10.10.230.230.24

代入程序, 利用Origin可绘制如下树木迭代相图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zsc_118

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值