[笔记]使用SFML来生成分形图片

9 篇文章 0 订阅
1 篇文章 0 订阅

前言

最近在上《优秀科普纪录片》时,看了一部有关 分形 的纪录片,在观看的过程中,想着自己也来生成一些分形图片,正好偶然了解到了SFML这个简单的图形库,所以天时地利人和,正好查一些资料来学习一下。

以下代码都是使用到SFML库的C++代码,所以如果要尝试使用的话,首先要配置好环境(我上一篇有介绍Cmake的配置方式,可以参考)

三分线段


看图就明白了吧。。


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>

using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");
float base = 100;
void getNextLine(float ax, float ay, float bx, float by, float len){
	if(len < 0.1f)return;
	float cx, cy, dx, dy, newLen;
	newLen = len / 3.0;
	cx = ax + newLen; cy = ay + base;
	dx = bx - newLen; dy = by + base;
	getNextLine(ax, ay + base, cx, cy, newLen);
	getNextLine(dx, dy, bx, by + base, newLen);
	sf::Vertex line[] = {
		sf::Vertex(sf::Vector2f(ax, ay), sf::Color::Cyan),
		sf::Vertex(sf::Vector2f(bx, by), sf::Color::Cyan)
	};
	window.draw(line, 2, sf::Lines);
	return;
}

int main(){
	window.clear();
	getNextLine(300, 300, 1600, 300, 1300);
	window.display();
	
	sf::Event event;
	while (window.isOpen()){
		while (window.pollEvent(event)){
			if (event.type == sf::Event::Closed) window.close();
		}
	}
	return 0;
}

分形树 FractralTree


这个生成的方式很简单,就是每次对一条线段取 2 3 \frac{2}{3} 32 然后对角度 + 60 和 − 30 +60和-30 +6030 来的到下一个线段的位置,不断地递归下去即可。


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>

using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");

void start(float inix, float iniy, float degree, float length)
{
	if (length < 1.0f) return;
	
	else
	{
		float newlength=0.67f * length;
		
		float finx = inix + (newlength * (float)cos(degree * (3.14 / 180.0f)));
		float finy = iniy + (newlength * (float)sin(degree * (3.14 / 180.0f)));
		
		sf::Vertex line[]= {
				sf::Vertex(sf::Vector2f(inix, iniy)),
				sf::Vertex(sf::Vector2f(finx, finy))
		};
		start(finx, finy, degree+60.0f, newlength);
		start(finx, finy, degree-30.0f, newlength);
		
		window.draw(line, 2, sf::Lines);
		//line.setFillColor(sf::Color::Blue);
		//window.display(); // Uncomment for animation
	}
}


int main()
{
	window.clear();
	start(1000, 799, -90, 350);
	window.display();
	
	sf::Event event;
	while (window.isOpen())
	{
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed) window.close();
		}
	}
	
	return 0;
}

Koch雪花


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>
const double pi = 3.1415926;
using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");
float base = 100;
void getNextLine(float ax, float ay, float bx, float by){
	float len = sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by));
	if(len < 1.0f){
		sf::Vertex line[] = {
			sf::Vertex(sf::Vector2f(ax, 1200 - ay), sf::Color::Cyan),
			sf::Vertex(sf::Vector2f(bx, 1200 - by), sf::Color::Cyan)
		};
		window.draw(line, 2, sf::Lines);
		return;	
	}
	float cx, cy, dx, dy, ex, ey, newLen;
	newLen = len / 3.0;
	cx = ax + (bx - ax) / 3; cy = ay + (by - ay) / 3;
	dx = bx - (bx - ax) / 3; dy = by - (by - ay) / 3;
	// float x = dx - cx, y = dy - cy;
	// ex = x * cos(pi / 3) - y * sin(pi / 3) + cx;
	// ey = x * sin(pi / 3) + y * cos(pi / 3) + cy;
	float a = atan((dy - cy)/(dx - cx));
	if(dx - cx < 0)a += pi;
	ex = cx + cos(a + pi/3) * newLen;
	ey = cy + sin(a + pi/3) * newLen; 
	getNextLine(ax, ay, cx, cy);
	getNextLine(cx, cy, ex, ey);
	getNextLine(ex, ey, dx, dy);
	getNextLine(dx, dy, bx, by);
	return;
}

int main(){
	window.clear();
	getNextLine(300, 600, 1600, 600);
	window.display();
	
	sf::Event event;
	while (window.isOpen()){
		while (window.pollEvent(event)){
			if (event.type == sf::Event::Closed) window.close();
		}
	}
	return 0;
}

当然计算ex, ey可以通过向量来搞

float x = dx - cx, y = dy - cy;
ex = x * cos(pi / 3) - y * sin(pi / 3) + cx;
ey = x * sin(pi / 3) + y * cos(pi / 3) + cy;

H树


关于H树的简介看这里


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>
const double pi = 3.1415926;
using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");

const float s2 = sqrt(2);
int num = 100;
void getNextLine(float x, float y, float len, bool v){
	if(len < 5.0f)return;
	// if(num-- < 0)return;
	float ax, ay, bx, by, newLen;
	newLen = len / s2;
	if(v){
		ax = x; ay = y - newLen;
		bx = x; by = y + newLen;
	}
	else{
		ax = x - newLen; ay = y;
		bx = x + newLen; by = y;
	}
	getNextLine(ax, ay, newLen, !v);
	getNextLine(bx, by, newLen, !v);
	sf::Vertex line1[] = {
		sf::Vertex(sf::Vector2f(ax, ay), sf::Color::Cyan),
		sf::Vertex(sf::Vector2f(bx, by), sf::Color::Cyan)
	};
	window.draw(line1, 2, sf::Lines);
	return;
}

int main(){
	window.clear();
	getNextLine(1000, 600, 300, 0);
	window.display();
	
	sf::Event event;
	while (window.isOpen()){
		while (window.pollEvent(event)){
			if (event.type == sf::Event::Closed) window.close();
		}
	}
	return 0;
}

当然你愿意搞得花里胡哨的话也不是不行


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>
#include<windows.h>
const double pi = 3.1415926;
using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");

const float s2 = sqrt(2);
float minLen = 500.0f;
const int maxn = 1e5 + 5;
struct lines{
	sf::Vertex line[2];
}lines[maxn];
int num = 0;
sf::Color colors[] = {sf::Color::Cyan, sf::Color::Red, sf::Color::Green, sf::Color::Yellow, sf::Color::White};
int c = 0;
void getNextLine(float x, float y, float len, bool v){
	if(len < minLen)return;
	// if(num-- < 0)return;
	float ax, ay, bx, by, newLen;
	newLen = len / s2;
	if(v){
		ax = x; ay = y - newLen;
		bx = x; by = y + newLen;
	}
	else{
		ax = x - newLen; ay = y;
		bx = x + newLen; by = y;
	}
	getNextLine(ax, ay, newLen, !v);
	++c; c %= 5;
	getNextLine(bx, by, newLen, !v);
	++c; c %= 5;
	// sf::Vertex line1[] = {
	// 	sf::Vertex(sf::Vector2f(ax, ay), sf::Color::Cyan),
	// 	sf::Vertex(sf::Vector2f(bx, by), sf::Color::Cyan)
	// };
	// lines[num].line[0] = sf::Vertex(sf::Vector2f(ax, ay), sf::Color::Cyan);
	// lines[num].line[1] = sf::Vertex(sf::Vector2f(bx, by), sf::Color::Cyan);
	lines[num].line[0] = sf::Vertex(sf::Vector2f(ax, ay), colors[c]);
	lines[num].line[1] = sf::Vertex(sf::Vector2f(bx, by), colors[c]);
	++num;
	// ++c; c %= 5;
	// window.draw(line1, 2, sf::Lines);
	return;
}
// int lnum = 0;
void dispaly(){
	// lnum = num;
	num = 0;
	getNextLine(1000, 600, 300, 0);
	minLen -= 5.0f;
	if(minLen < 5)minLen = 500;
	// if(num >= lnum * 2){
	// 	++c; c %= 5;
	// }
}
int main(){
	// window.clear();
	// getNextLine(1000, 600, 300, 0);
	// window.display();
	dispaly();
	sf::Clock clock;
	float timer = 0, delay = 0.1, time;
	sf::Event event;
	while (window.isOpen()){
		time = clock.getElapsedTime().asSeconds();
		timer += time;
		clock.restart();
		
		while (window.pollEvent(event)){
			if (event.type == sf::Event::Closed) window.close();
		}
		if(timer > delay){
			dispaly();
			timer = 0;
		}
		window.clear();
		for(int i = 0; i < num; ++i){
			window.draw(lines[i].line, 2, sf::Lines, sf::RenderStates::Default);
		}
		window.display();
	}
	return 0;
}

Julia集合

下面这份代码没有很好的调参,,所以,生成的图片也不怎么好看,等有时间修改一下在说吧。。


#include <iostream>
#include <cmath>
#include <SFML/Graphics.hpp>
#include<windows.h>
#include<complex>
const double pi = 3.1415926;
using namespace std;

sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");

sf::Color colors[10];
int col = 0;
void init(){
	for(int i = 0; i < 10; ++i){
		// colors[i] = sf::Color((128 - rand() % 128) + rand() % 128, (128 + rand() % 128) - rand() % 64, (100 + rand() % 120) - rand() % 100);
		// colors[i] = sf::Color((255 - rand() % 10 * i), (255 - rand() % 15 * i), (128 + rand() % 10 * i) % 255);
		colors[i] = sf::Color(i * 13, i * rand() % 255, i * 17);
	}
}
int getColor(double z){
	for(int i = 9; i >= 0; --i){
		// cout << i << endl;
		if(z <= 1.0 / (1 << i))return i;
	}
	return 0;
}
complex<double> c(-0.77097, -0.08545);
const int iter_max = 20;
complex<double> iter(complex<double> z){
	// cout << z << endl;
	for(int i = 1; i <= iter_max; ++i){
		z = z * z + c;
		if(std::abs(z) * std::abs(z) > 2)return z;
	}
	return z;
}

void drawText(string s){
	// Declare and load a font
	sf::Font font;
	cout << s << endl;
	font.loadFromFile("./res/consola.ttf");
	// Create a text
	sf::Text text(s, font);
	// text.setOrigin(sf::Vector2f(120, 100));
	text.setCharacterSize(30);
	text.setStyle(sf::Text::Bold);
	text.setFillColor(sf::Color::Red);
	// Draw it
	window.draw(text);
}

// int lnum = 0;
int num;
void dispaly(){
	// window.clear(sf::Color::Black);
	window.clear(sf::Color::White);
	// window.clear();
	c = complex<double>(rand() % 10000 / 23333.0f, rand() % 10000 / 10007.f);
	drawText("c: " + to_string(c.real()) + " " + to_string(c.imag()));
	num = 0;
	double x, y;
	int max_x = 800, max_y = 600;
	double base_x = 500, base_y = 300;
	complex<double> z;
	sf::VertexArray points;
	points.resize(0);
	int step = 1;
	for(int i = 0; i < max_x; i += step){
		if(i % 100 == 0)cout << i << endl;
		for(int j = 0; j < max_y; j += step){
			// 坐标变换
			x = 2 *(i - double(max_x) / 2.0) / (double(max_x) / 2.0);
			y = 1.33 * (j - double(max_y) / 2.0) / (double(max_y) / 2.0);
			z = iter(complex<double>(x, y));
			// points.append(sf::Vertex(sf::Vector2f(x, y), sf::Color::Cyan));


			// sf::Vertex p(sf::Vector2f(i + base_x, j + base_y), colors[getColor(std::abs(z))]);
			// points.append(p);
			// continue;

			if(std::abs(z) * std::abs(z) <= 2){
			// if(z.imag() * z.imag() + z.real() * z.real() < 2){
				// sf::Vertex p(sf::Vector2f(i + base_x, j + base_y), sf::Color::Cyan);
				sf::Vertex p(sf::Vector2f(i + base_x, j + base_y), colors[getColor(std::abs(z))]);
				points.append(p);
				// if(points.getVertexCount() > 100){
				// 	points.setPrimitiveType(sf::Points);
				// 	window.draw(points);
				// 	points.resize(0);
				// 	window.display();
				// }
				// cout << i << " " << j << endl;
			}
		}
	}
	points.setPrimitiveType(sf::Points);
	cout << points.getVertexCount() << endl;
	window.draw(points);
	points.resize(0);
	window.display();
}
int main(){

	init();
	dispaly();
	sf::Clock clock;
	float timer = 0, delay = 5, time;
	sf::Event event;
	while (window.isOpen()){
		time = clock.getElapsedTime().asSeconds();
		timer += time;
		clock.restart();
		// dispaly();
		while (window.pollEvent(event)){
			if (event.type == sf::Event::Closed) window.close();
		}
		if(timer > delay){
			dispaly();
			timer = 0;
		}
	}
	return 0;
}

(未完ing)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值