1. 程式人生 > >分形幾何演算法和實現

分形幾何演算法和實現

初識分形

1、分形的含義:

英文單詞Fractal,它是由美籍法國數學家曼德勃羅(Benoit Mandelbrot)創造出來的。其含義是不規則的、破碎的、分數的。曼德勃羅是想用此詞來描述自然界中傳統歐幾里得幾何學所不能描述的一大類複雜無規的幾何物件。

2、分形的幾何特徵:

自相似性:自相似,便是區域性與整體的相似。

自仿射性:自仿射性是自相似性的一種拓展。如果,將自相似性看成是區域性到整體在各個方向上的等比例變換的結果的話,那麼,自仿射性就是區域性到整體在不同方向上的不等比例變換的結果。前者稱為自相似變換,後者稱為自仿射變換。

精細結構:任意小區域性總是包含細緻的結構。

3、分形與電腦科學:

分形理論的發展離不開計算機圖形學的支援,如果一個分形構造的表達,不用計算機的幫助是很難讓人理解的。不僅如此,分形演算法與現有計算機圖形學的其他演算法相結合,還會產生出非常美麗的圖形,而且可以構造出複雜紋理和複雜形狀,從而產生非常逼真的物質形態和視覺效果。

分形作為一種方法,在圖形學領域主要是利用迭代、遞迴等技術來實現某一具體的分形構造。

分形幾何學與計算機圖形學相結合,將會產生一門新的學科——分形圖形學。它的主要任務是以分形幾何學為數學基礎,構造非規則的幾何圖素,從而實現分形體的視覺化,以及對自然景物的逼真模擬。

分形圖的遞迴演算法

遞迴演算法就不贅述了,凡是搞程式設計的應該都不陌生,可以參考我早前寫過的一些遞迴程式題目小練一下:《

遞迴練習(C語言)

以Koch曲線的遞迴演算法為例:

程式碼如下:

#include<stdio.h>
#include<math.h>
#include<conio.h>
#include"graphics.h"
void  koch(double x0, double y0, double x1, double y1, int k)
{
    double x2, y2, x3, y3, x4, y4;
    x2 = 2.0/3 * x0 + 1.0/3 * x1;  /*由上面的運算可以得到其餘三點 座標的計算式*/
    y2 = 2.0
/3 * y0 + 1.0/3 * y1; x3 = 1.0/3 * x0 + 2.0/3 * x1; y3 = 1.0/3 * y0 + 2.0/3 * y1; x4 = 1.0/2 * (x0 + x1) - sqrt(3.0)/6 * (y1 - y0); y4 = 1.0/2 * (y0 + y1) + sqrt(3.0)/6 * (x1 - x0); if( k > 1) /*如果迭代次數大於1,就繼續迭代下去,即執行以下程式*/ { koch(x0, y0, x2, y2, k - 1); /*對以(x0, y0)和(x2, y2)為端點的線段作為 初始線段進行迭代運算,以下類同*/ koch(x2, y2, x4, y4, k - 1); koch(x4, y4, x3, y3, k - 1); koch(x3, y3, x1, y1, k - 1); } else { /*如果迭代次數等於1,停止迭代,畫出迭代生成的圖形*/ line(x0, y0, x2, y2); /*用直線聯結兩點(x0, y0)和(x2, y2)*/ line(x2, y2, x4, y4); /*用直線聯結兩點(x2, y2)和(x4, y4)*/ line(x4, y4, x3, y3); /*用直線聯結兩點(x4, y4)和(x3, y3)*/ line(x3, y3, x1, y1); /*用直線聯結兩點(x3, y3)和(x1, y1)*/ } } int main() { int n, gdriver = DETECT, gmode; /*定義迭代次數n*/ initgraph(&gdriver, &gmode,"C:\\Win-TC\\BGI"); /*圖形系統初始化*/ printf("Please input the value of the positive integer n (n<9):"); scanf("%d", &n); /*輸入迭代次數n*/ setcolor(GREEN); koch(50, 120, 450, 120, n); getch(); closegraph(); /*關閉圖形系統*/ return 0; }

LS文法

LS文法先定義了繪圖規則:

F:以當前方向前進一步,並畫線;

f:以當前方向前進一步,不畫線;

+:逆時針旋轉角;

-:順時針旋轉角;

[:表示暫時儲存當前的畫圖狀態;

]:表示提取出儲存的畫圖狀態。 “[”“]”要成對的出現。

Koch曲線的LS文法如下:

 w:F(初始字母)

 a :60(旋轉角度)

 P:F → F + F - - F + F(F的替代文法)

根據這一文法生成Koch曲線的步驟(假設迭代兩次):

第一步: 得到迭代兩次的文法。

 第一次迭代結果:

             F + F - - F + F

 第二次迭代結果:(第一次迭代得到的結果的每一個F用規則P替換)

             F + F - - F + F + F + F - - F + F - - F + F - - F + F + F + F - - F + F

第二步:按照迭代得到的文法繪圖。

當然,還有實現其他分形圖的LS文法,這裡就不一一舉出了

下面的演算法沒有用遞迴,純C語言實現:

/****************************************************
** Completed on 2014.11.11 11:11
** Programming environment:win xp + win-tc 2.0
** Language: ANSI C
** copyright(c)  codingwu   (Email: [email protected])
*****************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<ctype.h>
#include<malloc.h>
#include<conio.h>
#include<graphics.h>

#define PI 3.1415926
#define stacksize 1024

typedef struct _point {
    double x;
    double y;
    double delta;
}point;

typedef struct _L_Sys {
    char *name;
    char *startStr; /* 初始字串 */
    char *replaceF;
    char *replaceX;  /* 替換X字串 */
    char *replaceY;  /* 替換Y字串 */
    char *replaceS;  /* 替換S字串 */
    char *replaceG;  /* 替換G字串 */
    char *replaceK;  /* 替換K字串 */
    char *replaceL;  /* 替換L字串 */
    char *replaceH;  /* 替換H字串 */
    int StartX;  /* 起始點座標 */
    int StartY;
    int depth;   /* 遞迴深度 */
    int ruleNumber;  /* 規則數 */
    double angle;
    double direct_init;
    double length;

}L_Sys;

L_Sys ls[100];

void init_L_Sys(L_Sys *LS, char *_name, char *_startStr, char *_replaceF,
        char *_replaceX, char *_replaceY, char *_replaceS, char *_replaceG,
        char *_replaceK, char *_replaceL, char *_replaceH,  int _StartX,
        int _StartY, int _depth, int _ruleNumber, double _angle,
        double _direct_init, double _length)    /* 初始化 */
{
    (*LS).name = (char *)malloc(strlen(_name) + 1);
    if((*LS).name == NULL) return;
    strcpy((*LS).name, _name);
    (*LS).startStr = (char *)malloc(strlen(_startStr) + 1);
    if((*LS).startStr == NULL) return;
    strcpy((*LS).startStr, _startStr);
    (*LS).replaceF = (char *)malloc(strlen(_replaceF) + 1);
    if((*LS).replaceF == NULL) return;
    strcpy((*LS).replaceF, _replaceF);
    (*LS).replaceX = (char *)malloc(strlen(_replaceX) + 1);
    if((*LS).replaceX == NULL) return;
    strcpy((*LS).replaceX, _replaceX);
    (*LS).replaceY = (char *)malloc(strlen(_replaceY) + 1);
    if((*LS).replaceY == NULL) return;
    strcpy((*LS).replaceY, _replaceY);
    (*LS).replaceS = (char *)malloc(strlen(_replaceS) + 1);
    if((*LS).replaceS == NULL) return;
    strcpy((*LS).replaceS, _replaceS);
    (*LS).replaceG = (char *)malloc(strlen(_replaceG) + 1);
    if((*LS).replaceG == NULL) return;
    strcpy((*LS).replaceG, _replaceG);
    (*LS).replaceK = (char *)malloc(strlen(_replaceK) + 1);
    if((*LS).replaceK == NULL) return;
    strcpy((*LS).replaceK, _replaceK);
    (*LS).replaceL = (char *)malloc(strlen(_replaceL) + 1);
    if((*LS).replaceL == NULL) return;
    strcpy((*LS).replaceL, _replaceL);
    (*LS).replaceH = (char *)malloc(strlen(_replaceH) + 1);
    if((*LS).replaceH == NULL) return;
    strcpy((*LS).replaceH, _replaceH);
    (*LS).StartX = _StartX;
    (*LS).StartY = _StartY;
    (*LS).depth = _depth;
    (*LS).ruleNumber = _ruleNumber;
    (*LS).angle = _angle;
    (*LS).direct_init = _direct_init;
    (*LS).length = _length;
}

void init(int n)
{
 /*init_L_Sys(&ls[i], "hualei", "Start", "F", "X", "Y", "S", "G", "K", "L", "H",
        pStartX, pStartY, depth, ruleNumber, angle, direct_init, length);          */
    switch(n) {
    case 0:
        init_L_Sys(&ls[0], "xiecao", "G", "F-XF", "", "", "",
            "GFX[+++++GFG][-----GFG]", "", "", "", 340, 20, 6, 2, -3, 60, 3.3);
        break;
    case 1:
        init_L_Sys(&ls[1], "shusan", "X", "FF", "--FXF++FXF++FXF--", "", "",
            "", "", "", "", 200, 50, 6, 2, -60, 0, 6);
        break;
    case 2:
        init_L_Sys(&ls[2], "hualei", "F", "F[+F[+F][-F]F][-F[+F][-F]F]F[+F][-F]F