畫個簡陋櫻花樹(簡單遞歸)

看到網上很多代碼繪製的櫻花樹,參見CSDN,便想自己試試,但是畫的有點醜

基本思路

其實就是一個“二叉樹的遍歷”的思路,使用遞歸不斷的二叉,就可以了,這也算是分形圖案了。但是簡單的遞歸二叉,不掌握好長度、角度、粗細以及主幹和枝幹的變化就會很規整。所以慢慢調參吧。

這裏採用的是給出每個參數的最大取值範圍,然後設置一個縮小的函數,隨着遞歸層數的提高,對應的參數越來越小,這個小的程度和範圍就要自己把握了。

縮小函數可以參考:1n,1n\frac{1}{n},\frac{1}{\sqrt{n}}

依賴

這裏的櫻花樹使用的是一個簡單的C++圖形庫 easyx,簡單容易上手。

演示

在這裏插入圖片描述

基礎代碼

#include <easyx.h>
#include <conio.h>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <iostream>

#define SEE(x) cout << #x << ":" << x << endl;
#define RED (RGB(240, 128, 128))
#define WHITE (RGB(255, 255, 255))
#define BROWN (RGB(160, 82, 45))

// 與主幹角度的偏移角度
const int angle_min = 18;
const int angle_max = 28;
// 長度
const int length_min = 60;
const int length_max = 90;
// 寬度
const int thick = 10;

// 繪製區大小
int width = 800, height = 600;

using namespace std;

typedef pair<int, int> Point;

// 繪製一條線
void drawline(Point st, Point ed) {
    line(st.first, st.second, ed.first, ed.second);
}

// 產生範圍內的隨機數
int rand_range(int st, int ed) {
    return st + rand() % (ed - st);
}

// 給點原點 相對於水平的角度 長度 返回處理後的節點
Point getPointFromAngle(Point src, float angle, int length) {
    angle = 3.14/180.0 * angle;
    return { src.first+length*cos(angle), src.second-length*sin(angle) };
}

// 遞歸畫叉
void draw_bifurcation(Point p, float angle, int layer) {
    // 結束層
    if (layer == 13) {
        return;
    }
    srand(time(NULL));
    // 偏移角
    float delta = rand_range(angle_min, angle_max);
    // 收縮 使用根號
    float shrink = pow(layer, 0.5);
    // 便宜的角度越來越小
    float left_angle = angle + delta/shrink;
    // 右分支的角度確定
    float right_angle = left_angle - 2.4*delta/shrink;
    // 隨機長度
    int length_left = rand_range(length_min / shrink, length_max / shrink);
    int length_right = rand_range(length_min / shrink, length_max / shrink);
    // 獲取下一個分支點
    Point left = getPointFromAngle(p, left_angle, length_left);
    Point right = getPointFromAngle(p, right_angle, length_right);
    // 末端繪製紅白相間的花瓣
    int type = rand() % 2;
    if (layer > 8) {
        if (type == 0) {
            setlinecolor(RED);
        }
        else {
            setlinecolor(WHITE);
        }
    }
    else {
        setlinecolor(BROWN);
    }
    // 設置厚度
    setlinestyle(PS_SOLID , thick/layer);
    drawline(p, left);
    // 遞歸左分支
    draw_bifurcation(left, left_angle, layer + 1);
    setlinestyle(PS_SOLID, thick / layer);
    if (layer > 8) {
        if (type == 0) {
            setlinecolor(WHITE);
        }
        else {
            setlinecolor(RED);
        }
    }
    else {
        setlinecolor(BROWN);
    }
    // 動態效果
    Sleep(1);
    drawline(p, right);
    // 遞歸右分支
    draw_bifurcation(right, right_angle, layer + 1);
}

// 隨機繪製地面的花瓣
void draw_ground() {
    int left = width * 0;
    int right = width * 1;
    int up = height - 60;
    int down = height;
    int length = 4;
    setlinecolor(RED);
    setlinestyle(PS_SOLID, 3);
    int x, y, angle;
    for (int i = 0; i < 300; i++) {
        x = rand_range(left, right);
        y = rand_range(up, down);
        angle = rand_range(0, 360);
        Point ed = getPointFromAngle({ x, y }, angle, length);
        Sleep(5);
        drawline({ x, y }, ed);
    }
}

int main() {
    initgraph(width, height);
    // 設置背景色
    setbkcolor(RGB(241, 215, 118));
    cleardevice();
    // 繪製主幹
    setlinecolor(BROWN);
    setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 10);
    line(width/2, height-110, width/2, height-20);
    // 遞歸繪製
    draw_bifurcation({ width/2, height-110 }, 90.0, 1);
    // 繪製掉落花瓣的地面
    draw_ground();
    _getch();
    closegraph();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章