首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 遞迴繪製分形圖形:科赫曲線、謝爾賓斯基三角形、分形矩形與分形樹完整實作

     編輯:關於VC++

前言:分形幾何與遞迴之美

分形透過簡單規則重複套用,產生無限複雜的自我相似結構。VC++ 配合 `CDC` 繪圖裝置,輕鬆實作經典分形。本文提供四種分形的完整遞迴函式與幾何計算,可直接整合至 `OnDraw` 或按鈕事件中。

通用繪圖輔助


// 於 OnDraw 或繪圖函式中取得 CDC*
void DrawFractals(CDC* pDC) {
    // 科赫曲線
    Koch(pDC, 100, 300, 500, 300, 5);
    // 謝爾賓斯基三角形
    Sierpinski(pDC, 300, 50, 100, 400, 500, 400, 5);
    // 分形矩形
    FractalRect(pDC, 100, 100, 400, 300, 4);
    // 分形樹
    FractalTree(pDC, 300, 400, 300, 100, 6);
}

1. 科赫曲線

將線段三等分,中段替換為等邊三角形兩側,遞迴套用。


void Koch(CDC* pDC, int x1, int y1, int x2, int y2, int n) {
    if (n <= 0) return;

    int x3 = x1 + (x2 - x1) / 3;
    int y3 = y1 + (y2 - y1) / 3;
    int x4 = x1 + (x2 - x1) * 2 / 3;
    int y4 = y1 + (y2 - y1) * 2 / 3;
    // 等邊三角形頂點 (向上凸)
    int x5 = x3 + (x4 - x3) / 2 + (int)(sqrt(3.0) * (y4 - y3) / 2);
    int y5 = y3 - (int)(sqrt(3.0) * (x4 - x3) / 2) + (y4 - y3) / 2;

    if (n == 1) {
        pDC->MoveTo(x1, y1);
        pDC->LineTo(x3, y3);
        pDC->LineTo(x5, y5);
        pDC->LineTo(x4, y4);
        pDC->LineTo(x2, y2);
    } else {
        Koch(pDC, x1, y1, x3, y3, n-1);
        Koch(pDC, x3, y3, x5, y5, n-1);
        Koch(pDC, x5, y5, x4, y4, n-1);
        Koch(pDC, x4, y4, x2, y2, n-1);
    }
}

幾何關鍵:旋轉向量 `(x4-x3, y4-y3)` 正負 60° 得到頂點。第 5 階段已極細緻,建議 `n <= 6`。

2. 謝爾賓斯基三角形

三角形連接三邊中點形成中央倒三角形移除,對三個角遞迴。


void Sierpinski(CDC* pDC, int x1, int y1, int x2, int y2, int x3, int y3, int n) {
    if (n <= 0) return;

    int x12 = (x1 + x2) / 2, y12 = (y1 + y2) / 2;
    int x23 = (x2 + x3) / 2, y23 = (y2 + y3) / 2;
    int x31 = (x3 + x1) / 2, y31 = (y3 + y1) / 2;

    // 畫中央倒三角形邊框 (可選)
    pDC->MoveTo(x12, y12); pDC->LineTo(x23, y23);
    pDC->MoveTo(x23, y23); pDC->LineTo(x31, y31);
    pDC->MoveTo(x31, y31); pDC->LineTo(x12, y12);

    if (n == 1) {
        // 畫最小三角形實心或邊框
        pDC->MoveTo(x12, y12); pDC->LineTo(x23, y23);
        pDC->LineTo(x31, y31); pDC->LineTo(x12, y12);
    } else {
        // 三個角遞迴
        Sierpinski(pDC, x1, y1, x31, y31, x12, y12, n-1); // 左上
        Sierpinski(pDC, x12, y12, x2, y2, x23, y23, n-1); // 右上
        Sierpinski(pDC, x31, y31, x23, y23, x3, y3, n-1); // 底部
    }
}

3. 分形矩形

矩形內嵌旋轉正方形,對四個小矩形遞迴。


void FractalRect(CDC* pDC, int x1, int y1, int x2, int y2, int n) {
    if (n <= 0) return;

    int x3 = x1 + (x2 - x1) / 3, y3 = y1 + (y2 - y1) / 3;
    int x4 = x1 + (x2 - x1) * 2 / 3, y4 = y1 + (y2 - y1) * 2 / 3;
    // 內嵌正方形四頂點 (逆時針 90° 旋轉)
    int x5 = x3 + (y4 - y3), y5 = y3 - (x4 - x3);
    int x6 = x4 - (y4 - y3), y6 = y4 + (x4 - x3);

    pDC->MoveTo(x1, y1); pDC->LineTo(x3, y3);
    pDC->MoveTo(x4, y4); pDC->LineTo(x2, y2);

    if (n == 1) {
        pDC->MoveTo(x1, y1); pDC->LineTo(x3, y3);
        pDC->LineTo(x5, y5); pDC->LineTo(x6, y6);
        pDC->LineTo(x4, y4);
    } else {
        FractalRect(pDC, x3, y3, x5, y5, n-1);
        FractalRect(pDC, x5, y5, x6, y6, n-1);
        FractalRect(pDC, x6, y6, x4, y4, n-1);
    }
}

4. 分形樹

主幹分叉為三支 (中、左、右),角度 ±150°,長度遞減。


const double PI = 3.14159265358979323846;

void FractalTree(CDC* pDC, int x1, int y1, int x2, int y2, int n) {
    if (n <= 0) return;

    int x3 = x1 + (x2 - x1) / 3;
    int y3 = y1 + (y2 - y1) / 3;
    // 向量 (x1-x3, y1-y3) 旋轉 ±150° (5π/6)
    double cos150 = cos(5*PI/6), sin150 = sin(5*PI/6);
    int dx = x1 - x3, dy = y1 - y3;

    int x4 = x3 + (int)(dx * cos150 - dy * sin150);
    int y4 = y3 + (int)(dx * sin150 + dy * cos150);
    int x5 = x3 + (int)(dx * cos150 + dy * sin150);
    int y5 = y3 - (int)(dx * sin150 - dy * cos150);

    pDC->MoveTo(x1, y1); pDC->LineTo(x2, y2); // 主幹

    if (n == 1) {
        pDC->MoveTo(x3, y3); pDC->LineTo(x4, y4);
        pDC->MoveTo(x3, y3); pDC->LineTo(x5, y5);
    } else {
        FractalTree(pDC, x3, y3, x2, y2, n-1); // 中央延伸
        FractalTree(pDC, x3, y3, x4, y4, n-1); // 左分支
        FractalTree(pDC, x3, y3, x5, y5, n-1); // 右分支
    }
}

效能與優化建議

  • 遞迴深度限制:`n > 7` 會導致指數級線段增長,建議上限 6~7
  • 雙重緩衝:在記憶體 DC 繪製完成後 `BitBlt` 到螢幕,防止閃爍
  • 整數運算優化:預計算 `sin/cos` 查表、定點數運算
  • 裁剪區域:`pDC->IntersectClipRect` 限制繪製範圍
  • 多執行緒:將不同分支分派至執行緒池 (需同步 DC 存取)

擴充想法

  1. 顏色漸變:依遞迴深度 `n` 插值 RGB
  2. 動畫生長:用 Timer 逐幀增加 `n` 並 `Invalidate`
  3. 互動參數:滑桿調整角度、縮放比、分支數
  4. 3D 分形:配合 OpenGL/DirectX 渲染曼德博集合、朱利亞集合
  5. 輸出向量圖:改寫繪圖指令輸出 SVG/DXF
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved