I have some code that I'd like to optimize if possible beside lowering the maximum number of iterations. I've heard there is some way to detect a cyclic but I've tried to implement it in different ways and either it became slower or it did garbage. The display functions are not shown since it is not the cause of the slow down.
#pragma once
#include <SFML/Graphics/Rect.hpp>
#include <SFML/System/Vector2.hpp>
#include <cstdint>
#include <complex>
#include <functional>
#include <vector>
using namespace std;
template<class T>
class Fractal
{
public:
Fractal(void);
~Fractal(void);
//the most important function
vector<uint32_t> evaluate(const sf::Rect<T>& area, const sf::Vector2u& subdivisions);
//set the iterative function
typedef function<void(complex<T>&)> iterative_function;
void setIterativeFunction(iterative_function func);
//set the domain function
typedef function<bool(complex<T>&)> domain_function;
void setDomainFunction(domain_function func);
//set the maximum number of escape iterations
void setMaxIterations(const uint32_t iterations);
//get maximum iterations
uint32_t getMaxIterations() const;
//a coordinates generator
//generates the coordinates to evaluate the fractal
class CoordinatesGenerator
{
public:
CoordinatesGenerator(const sf::Rect<T>& area, const sf::Vector2u& subdivisions);
~CoordinatesGenerator();
complex<T> operator()();
private:
const sf::Rect<T>& area_;
const sf::Vector2u& subdivisions_;
complex<T> coord_;
sf::Vector2u pixel_;
};
private:
//the number of escape iterations
uint32_t max_iterations_;
//the tolerance where z must change
T tolerance_;
//the formula used for the iterative system
iterative_function iter_function_;
//the formula that decides either the given complex is inside or not the domain
domain_function domain_function_;
//returns the number of iterations that z has to do to escape
uint32_t getIterations(complex<T> z) const;
};
template<class T>
Fractal<T>::Fractal()
{
//setting max iterations to 1000 by default
max_iterations_ = 1000;
//setting standard Manderbot iterative function
iter_function_ = iterative_function([](complex<T>& z)
{
z = z*z + complex<T>(1,0);
});
//setting standard Manderbot domain function
domain_function_ = domain_function([](complex<T>& z)
{
return abs(z) < 2;
});
}
// Fractal<T>::setIterativeFunction
// iterative_function func : the function on which the system iterates
// must match this signature : void(Complex<T>&)
template<class T>
void Fractal<T>::setIterativeFunction(iterative_function func)
{
iter_function_ = func;
}
// Fractal<T>::setDomainFunction
// domain_function func : the function that determines if complex is inside domain
// must match this signature : bool(Complex<T>&)
template<class T>
void Fractal<T>::setDomainFunction(domain_function func)
{
domain_function_ = func;
}
// Fractal<T>::setMaxIterations
// iterations : set the maximum iterations for escape
template<class T>
void Fractal<T>::setMaxIterations(const uint32_t iterations)
{
max_iterations_ = iterations;
}
// vector<uint32_t> Fractal<T>::evaluate(const sf::Rect<T>& area, const sf::Vector2u& subdivisions)
// area: the fractal area to evaluate
// subdivisions : the number of subdivisions to evaluate
// return a vector of the number of iterations
// the vector is construction from x = 0 ... n, y = 0 ... n
template<class T>
vector<uint32_t> Fractal<T>::evaluate(const sf::Rect<T>& area, const sf::Vector2u& subdivisions)
{
uint32_t temp;
complex<T> z(area.left,area.top);
uint32_t num_coordinates = (subdivisions.x)*(subdivisions.y);
vector<uint32_t> result;
vector<complex<T>> coordinates(num_coordinates);
CoordinatesGenerator generator(area,subdivisions);
generate(coordinates.begin(),coordinates.end(),generator);
for(auto& z: coordinates)
{
temp = getIterations(z);
result.push_back(temp);
}
return result;
}
// uint32_t Fractal<T>::getIterations(complex<T> z) const
// z : the complex number to evaluate
// return the number of iterations that z escapes domain
// using iterative and domain functions
template<class T>
uint32_t Fractal<T>::getIterations(complex<T> z) const
{
static uint32_t result;
result = 0;
while(domain_function_(z) && result < max_iterations_)
{
iter_function_(z);
result++;
}
return result;
}
// Fractal<T>::CoordinatesGenerator::CoordinatesGenerator(const sf::Rect<T>& area, const sf::Vector2u& subdivisions)
// area : the fractal area to evaluate
// subdivisions : the number of subdivisions
// used by STL algorithm
template<class T>
Fractal<T>::CoordinatesGenerator::CoordinatesGenerator(const sf::Rect<T>& area, const sf::Vector2u& subdivisions):
area_(area),subdivisions_(subdivisions)
{
coord_ = complex<T>(area_.left,area_.top);
pixel_.x = 0;
pixel_.y = 0;
}
template<class T>
Fractal<T>::CoordinatesGenerator::~CoordinatesGenerator()
{
}
// complex<T> Fractal<T>::CoordinatesGenerator::operator()()
// Generate coordinates to evaluate the fractal
// used by STL algorithm
template<class T>
complex<T> Fractal<T>::CoordinatesGenerator::operator()()
{
//getting the variation of X and Y
T deltaX = area_.width/static_cast<T>(subdivisions_.x);
T deltaY = area_.height/static_cast<T>(subdivisions_.y);
//creating the coordinate
coord_ = complex<T>(static_cast<T>(pixel_.x)*deltaX + area_.left,static_cast<T>(pixel_.y)*deltaY + area_.top);
//applying some changes to generate the next coordinate
pixel_.x++;
if(pixel_.x >= subdivisions_.x)
{
pixel_.y++;
pixel_.x = 0;
}
return coord_;
}
template<class T>
Fractal<T>::~Fractal()
{
}
template<class T>
uint32_t Fractal<T>::getMaxIterations() const
{
return max_iterations_;
}
I noticed that your function returns
Please make sure that you use C++11 enabled compilier as you are likely to benefit from move semantics.