Fractal programming - Any way to optimize this code for real time rendering?

761 Views Asked by At

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_;
}
1

There are 1 best solutions below

0
On

I noticed that your function returns

vector<uint32_t> 

Please make sure that you use C++11 enabled compilier as you are likely to benefit from move semantics.