仿射变换生成分形

在学习仿射变换的时候,我们对仿射变换对二维图形的作用很满意,它能满足平移,旋转, 伸缩和错切等特性。 而且相对于之前的共形几何,仿射几何变换似乎更强大,那么我们之前用Logo语言绘制出来的那些分形图形是否也可以利用仿射几何搞定呢?

那最简单的三角形地垫来讲: 首先是一个大的三角形:然后分别以三个顶点A, B, C,按1/2的比例放缩, 可以得到

 

那么从第二个到第三个图形呢, 我们还是分别以三个顶点A, B, C,对第二个图形,按1/2的比例放缩。

那么具体是如何操作的呢?

操作的关键在于 :我们要保证一个三角形在放缩了以后还是三角形。就是说我们要以三角形个体来考虑。

看一下以下代码:

struct myPolygon
{
    myPolygon() = default;
    // 多边形的顶点。
    myPolygon(const std::vector<D2D1_POINT_2F>& peaks) : m_Peaks (peaks){}


    void Draw(ID2D1HwndRenderTarget** render, ID2D1SolidColorBrush** soildbrush)
    {
        int i = 0;
        for (; i != m_Peaks.size() - 1; ++i)
        {
            (*render)->DrawLine(m_Peaks[i], m_Peaks[i + 1], *soildbrush); // 连接相邻的顶点。
        }
        (*render)->DrawLine(m_Peaks[i], m_Peaks[0], *soildbrush);
    }

    std::vector<D2D1_POINT_2F> m_Peaks;  //存储多边形的顶点
};

上面的代码是多边形的,包含三角形。

我们对图形的变换都是相同的:以A, B, C顶点, 按1/2 比例放缩。 然后针对所有的三角形。

看一下主代码里面是如何使用它的:

//1. 得到窗口的大小。
        D2D1_SIZE_F size = m_pRenderTarget->GetSize();

        //2. 给定多边形的中心
        D2D1_POINT_2F Center = D2D1::Point2F(size.width / 2, size.height / 2);

        //3. 以200为半径的多边形, 得到初始多边形所有的顶点。
        const int Length = 200;
        std::vector<D2D1_POINT_2F> Peaks;
        for (int i = 0; i != EdgesNum; ++i)
        {
            Peaks.push_back(D2D1::Matrix3x2F::Rotation(360 * i / EdgesNum, Center).TransformPoint(D2D1::Point2F(size.width / 2, size.height / 2 -Length)));
        }

        //4. 得到所有以初始多边形为顶点, 按0.5放缩的仿射变换矩阵。
        std::vector<D2D1::Matrix3x2F> MatrixScale;
        for (auto& peak : Peaks)
        {
            MatrixScale.push_back(D2D1::Matrix3x2F::Scale(0.5, 0.5, peak));
        }

        //5. 用来存放后续生成的所有多边形。刚开始里面只有一个初始多边形。
        std::vector<myPolygon> vecPolygon;
        vecPolygon.push_back(myPolygon(Peaks));
        
        int level = 5;  //分层级数
        while (level != 0)
        {
            //用来临时存放因对这一层图形进行仿射变换,而产生的所有多边形。
            std::vector<myPolygon> temp;

            for (auto& Mscale : MatrixScale)  //以某一点的变换矩阵
            {
                for (auto& polygon : vecPolygon)  //对所有的多边形进行变换
                {
                    myPolygon pg;                  //存放变换后的多边形。
                    for (auto& peak : polygon.m_Peaks)  //对该多边形的顶点进行变换。
                    {
                        pg.m_Peaks.push_back(Mscale.TransformPoint(peak));
                    }
                    temp.push_back(pg);    //把该临时多边形放进容器。
                }
            }
            vecPolygon = temp;  //把变换后得到的所有多边形顶点付给初始容器,使它作为下一次层级变换的初始图形。
            --level;
        }

        //绘制最后生成的所有多边形。
        for (auto& poly : vecPolygon)
        {
            poly.Draw(&m_pRenderTarget, &m_pLightSlateGrayBrush);
        }

最后看看生成的图片吧。

上面这个是5边形, 按照0.5的比例放缩的。

这个是五边形,是按照0.4的比例缩放的。

这个是六边形,按照0.4的比例缩放的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值