谢尔平斯基三角形是一组多个(或无限)三角形。看看下面的谢尔平斯基三角形,看看它看起来有多无限。
这里的概念是,填充的三角形由中心的空等边三角形填充,使得这个三角形空间与围绕它形成的三个三角形一致。

如下图所示 ,我们将要使用的概念很简单。如果有一个或多个图块,而不是在图块空间上方的三个图块,那么,我们将在该空间中放置一个图块,否则,就没有图块!
也就是说我们只在黑三角里面放置白三角,其余地方不放。

文件有三个,分别是:main.cpp、SierpinskiTile.h、SierpinskiTile.cpp
在 SierpinskiTile.h 中:
我们需要包含 SDL.h 用于绘图和列表,以便包含SDL_Rect* 或图块的列表。
- #include <SDL.h>
- #include <list>
-
- #ifndef _SIERPINSKI_TILE_
- #define _SIERPINSKI_TILE_
-
- class SierpinskiTile
- {
- public:
- SierpinskiTile(int scrW, int scrH, int w, int h)
- : scrW(scrW), scrH(scrH), tileW(w), tileH(h) {};
- ~SierpinskiTile();
- void setTile(int x_index, int y_index);
- bool isThereTile(int x_index, int y_index);
- void calculate(int y_index = -1);
- void draw(SDL_Renderer*& renderer, int r, int g, int b, int y_index);
-
- private:
- int scrW, scrH;
- int tileW, tileH;
- std::list<SDL_Rect*> rects;
- };
-
- #endif
SierpinskiTile.cpp文件内容如下:
- #include "SierpinskiTile.h"
-
- SierpinskiTile::~SierpinskiTile() //Deleting all resources in destructor
- {
- for (auto itr : rects)
- delete itr;
- }
-
- //setTile() 方法在磁贴索引位置上设置小三角片:
- void SierpinskiTile::setTile(int x_index, int y_index) //Setting tile on the tile index position
- {
- SDL_Rect* rectToAdd = new SDL_Rect;
- rectToAdd->x = x_index * tileW;
- rectToAdd->y = y_index * tileH;
- rectToAdd->w = tileW;
- rectToAdd->h = tileH;
-
- rects.push_back(rectToAdd);
- }
-
- //isThereTile() 方法,用于找出给定的磁贴索引位置是否具有小三角片:
- bool SierpinskiTile::isThereTile(int x_index, int y_index) //Finding out whether a tile is here or not
- {
- for (auto itr : rects)
- if (itr->x == tileW * x_index
- && itr->y == tileH * y_index)
- return true;
-
- return false;
- }
-
-
-
- //compute() 方法找出下一行的小三角片排列,默认参数为 -1,这将导致 calculate()方法计算所有行的磁贴排列:
- void SierpinskiTile::calculate(int y_index) //Calculating where to put tiles in the next row
- //by the tile arrangement present in the previous row
- {
- /
- //Conditions for putting a tile below the upper tile (or tile space):
- // 1- Tile is at that spot, 0- Tile is not at that spot, X- Unknown (can be 0 or 1)
-
- /
- // Case 1: 0 1 0, Case 2: 1 0 0, Case 3: 0 0 1,
- // Case 4: 1 1 0, Case 5: 1 0 1, Case 6: 0 1 1
-
- // Output for Cases 1-6: X 1 X
-
- /
- // Case 7: 0 0 0, Case 8: 1 1 1
-
- // Output for Cases 7-8: X 0 X
-
- int y = 0;
- if (y_index > -1)
- {
- y = y_index;
-
- for (int x = 0; x < scrW / tileW; x++)
- {
- if ((isThereTile(x, y) || isThereTile(x + 1, y) || isThereTile(x - 1, y))
- && !(isThereTile(x, y) && isThereTile(x + 1, y) && isThereTile(x - 1, y))
- )
- setTile(x, y + 1);
- }
- }
- else
- {
- for (; y < scrH / tileH; y++)
- for (int x = 0; x < scrW / tileW; x++)
- {
- if ((isThereTile(x, y) || isThereTile(x + 1, y) || isThereTile(x - 1, y))
- && !(isThereTile(x, y) && isThereTile(x + 1, y) && isThereTile(x - 1, y))
- )
- setTile(x, y + 1);
- }
- }
- }
-
-
- // draw() 方法实际上只绘制一行并删除前面所有行中的所有小三角片:
- void SierpinskiTile::draw(SDL_Renderer*& renderer, int r, int g, int b, int y_index)
- {
- SDL_SetRenderDrawColor(renderer, r, g, b, 255); //Setting renderer's color
-
- std::list<SDL_Rect*> deleteRects; //For getting a list of rectangles/tiles to be deleted
- for (auto itr : rects)
- {
- SDL_RenderFillRect(renderer, itr); //Draw all tiles present in the rects which
- //will be just all tiles in the particular row
-
- if (itr->y <= tileH * y_index) //Put all tiles of rows before the given row
- //to deleteRects for deleting
- deleteRects.push_back(itr);
- }
-
- for (auto itr : deleteRects) //Delete all collected tiles and clear them
- {
- rects.remove(itr);
- delete itr;
- }
- deleteRects.clear();
-
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); //Resetting renderer's color
- }
main.cpp文件,首先,我们需要一些必要的常量以及SDL_Window*,SDL_Renderer*和SDL_Event,此外我们还需要一个布尔值。
- #include <SDL.h>
- #include "SierpinskiTile.h"
-
- #undef main //Solution to the problem: No entry point defined.
-
- const int SCR_W = 640;
- const int SCR_H = 480;
- const int TILE_W = 5; //Each tile's width
- const int TILE_H = 5; //Each tile's height
-
- SDL_Window* window = NULL;
- SDL_Renderer* renderer = NULL;
- SDL_Event event;
-
- bool quit = false;
-
- SierpinskiTile* generator = NULL;
-
- int main(int argc, char** args)
- {
- SDL_Init(SDL_INIT_VIDEO); //Initializing SDL2
-
- window = SDL_CreateWindow("Koch Fractal", SDL_WINDOWPOS_UNDEFINED,
- SDL_WINDOWPOS_UNDEFINED, SCR_W, SCR_H, SDL_WINDOW_SHOWN); //Creating window
- renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); //Creating renderer
-
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); //Setting default screen color
-
- generator = new SierpinskiTile(SCR_W, SCR_H, TILE_W, TILE_H); //Creating fractal generator
- generator->setTile((SCR_W / TILE_W) / 2, 0); //Setting a tile at the top middle of the screen
-
- int row = 0;
- while (!quit)
- {
- while (SDL_PollEvent(&event) > 0) //Minimal event polling for proper quitting
- if (event.type == SDL_QUIT)
- quit = true;
-
- //***NOTE: Screen must not be cleaned as the draw() method draws a row only
- //and deletes all tiles of the previous rows***
- //SDL_RenderClear(renderer);
-
- if (row < SCR_H / TILE_H) //Draw and calculate until the last row
- {
- generator->draw(renderer, 0, 255, 0, row-1); //Drawing the row in green color
-
- SDL_RenderPresent(renderer); //Updating screen
-
- generator->calculate(row++); //Calculating the next row
- }
- }
-
- delete generator; //Deallocating fractal generator
-
- SDL_DestroyRenderer(renderer);
- SDL_DestroyWindow(window);
- SDL_Quit(); //Clearing all SDL resources
-
- return 0;
- }
下图显示了结果,细节取决于常量TILE_W和TILE_H。值越小,分形显示的细节就越详细。
