Snippets

Neural Outlet Rauzy Fractal Problem

Created by Neural Outlet last modified
#include "widget.h"
#include "ui_widget.h"

#include <QLabel>
#include <QGridLayout>

#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
#include <QMatrix4x4>

#include <iostream>
#include <vector>

//Some global colours for ease.
QRgb g_Black = QColor::fromRgb(0,0,0).rgb();
QRgb g_Grey = QColor::fromRgb(127,127,127).rgb();
QRgb g_White = QColor::fromRgb(255,255,255).rgb();

//To keep colour with point
struct Point{
    qreal _x,_y,_z;
    QRgb _c;
    Point(qreal x, qreal y, qreal z){
        _x=x; _y=y; _z=z;
    }
    QVector3D ToQVec(){ return QVector3D(_x, _y, _z); }
};

//Tribonacci word generator
QString TribWord(int cycle)
{
    QString word("1");
    QString temp("");
    for(int i = 0; i < cycle; ++i)
    {
        for(int j = 0; j < word.size(); ++j)
        {
            if(word[j] == '1')
                temp += "12";
            if(word[j] == '2')
                temp += "13";
            if(word[j] == '3')
                temp += "1";
        }
        word = temp;
        temp = "";
    }
    return word;
}


//The Orthographic Projection function:
QVector2D OrthoProj(QVector3D point)
{
    //Unit cube
    qreal left = -1, bottom = -1, nearPlane = 1;
    qreal right = 1, top = 1, farPlane = -1;

    // Construct the projection.
    qreal width = right - left;
    qreal invheight = top - bottom;
    qreal clip = farPlane - nearPlane;

    //Orthographic projection matrix
    QGenericMatrix<4,4,qreal> m; m.fill(1);
    m(0,0) = 2.0f / width;
    m(1,0) = 0.0f;
    m(2,0) = 0.0f;
    m(3,0) = -(left + right) / width;
    m(0,1) = 0.0f;
    m(1,1) = 2.0f / invheight;
    m(2,1) = 0.0f;
    m(3,1) = -(top + bottom) / invheight;
    m(0,2) = 0.0f;
    m(1,2) = 0.0f;
    m(2,2) = -2.0f / clip;
    m(3,2) = -(nearPlane + farPlane) / clip;
    m(0,3) = 0.0f;
    m(1,3) = 0.0f;
    m(2,3) = 0.0f;
    m(3,3) = 1.0f;


    QGenericMatrix<4,1,qreal> m2;
    m2(0, 0) = point.x();
    m2(0, 1) = point.y();
    m2(0, 2) = point.z();
    m2(0, 3) = 1.0;

    // Apply the projection.
    QGenericMatrix<4,1,qreal> m3 = m2 * m;
    //std::cout << "(" << m2(0,0) << ", " << m2(0,1) << ", " << m2(0,2) << ", " << m2(0,3) << ")" << std::endl;
    //std::cout << "times" << std::endl;
    //std::cout << "|" << m(0,0) << ", " << m(0,1) << ", " << m(0,2) << ", " << m(0,3) << "|" << std::endl;
    //std::cout << "|" << m(1,0) << ", " << m(1,1) << ", " << m(1,2) << ", " << m(1,3) << "|" << std::endl;
    //std::cout << "|" << m(2,0) << ", " << m(2,1) << ", " << m(2,2) << ", " << m(2,3) << "|" << std::endl;
    //std::cout << "|" << m(3,0) << ", " << m(3,1) << ", " << m(3,2) << ", " << m(3,3) << "|" << std::endl;
    //std::cout << "equals" << std::endl;
    //std::cout << "|" << m3(0,0) << ", " << m3(0,1) << ", " << m3(0,2) << ", " << m3(0,3) << "|" << std::endl;

    return QVector2D(m3(0,0), m3(0,1));
}

//Takes the tribonacci word, iterates through it creating the
//staircase of 3D points, then uses the last one to scale the others
//and projects it onto a 2D plane.
QImage RauzyPlane(QString tribonacci)
{
    Point end(0,0,0);
    std::vector<Point> stairs;
    std::vector<Point>::iterator iter = stairs.begin();
    stairs.push_back(Point(0,0,0));
    for(int i = 0; i < tribonacci.size(); ++i)
    {
        Point step = stairs[i];
        if(tribonacci[i] == '1')
        {
            step._x += 1;
            step._c = QColor::fromRgb(255,0,0).rgb();
        }
        if(tribonacci[i] == '2')
        {
            step._y += 1;
            step._c = QColor::fromRgb(0,255,0).rgb();
        }
        if(tribonacci[i] == '3')
        {
            step._z += 1;
            step._c = QColor::fromRgb(0,0,255).rgb();
        }
        stairs.push_back(step);
        end = step;
    }
    std::cout << "# of stair points: " << stairs.size() << std::endl;
    std::cout << "Stair end: " << end._x << ", " << end._y  << ", " << end._z << std::endl;

    //Create the image with a grey background
    QImage img(100,100,QImage::Format_ARGB32);
    for(int a = 0; a < 100; ++a)
    {
        for(int b = 0; b < 100; ++b)
        {
            img.setPixel(a,b,g_Grey);
        }
    }

    //for each point n the staircase, project it to the 2D plane
    for(iter = stairs.begin(); iter != stairs.end(); ++iter)
    {
        //Normalise the point by the end point
        QVector3D proj = (*iter).ToQVec();
        proj.setX(proj.x()/end._x);
        proj.setY(proj.y()/end._y);
        proj.setZ(proj.z()/end._z);
        QVector2D pos = OrthoProj(proj);

        //Scale for screen
        qreal xOut = 50 + (pos.x() * 25);
        qreal yOut = 50 + (pos.y() * 25);

        if(xOut < 0 || xOut > 100)
            std::cout << "X ERR: " << xOut << std::endl;

        if(yOut < 0 || yOut > 100)
            std::cout << "Y ERR: " << yOut << std::endl;

        //Colout the new pixel with its corrosponding colour
        img.setPixel(xOut, yOut, (*iter)._c);
    }
    return img;
}



// The actual widet
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowTitle("Not a Rauzy Fractal");

    //Generate a tribonacci word of 15 cycles
    QString trib = TribWord(15);

    //Create fractal based on the word
    QImage blah = RauzyPlane(trib);

    //Set centre pixel as black
    blah.setPixel(50,50,g_Black);

    //Create label to show image
    QLabel *label = new QLabel;
    label->setPixmap(QPixmap::fromImage(blah.scaled(500,500)));

    //Create layout and add the image
    QGridLayout *lay = new QGridLayout;
    lay->addWidget(label);
    setLayout(lay);
    show();
}

Widget::~Widget()
{
    delete ui;
}

/*

 the substitution: 1 -> 12, 2 -> 13, 3 -> 1
 has the incidence matrix:

   1 1 0
   1 0 1
   1 0 0

 which has the approx eigenvector:

   ω = ⟨ω1,ω2,ω3⟩ = ⟨-0.412+0.6i, 0.223-1.12i, 1⟩

  and the mapping function is the count of amount of instances of character N in the substitution string U:

  sum foreach n: |U|_n * ω_n

  the resulting value is a single complex number.
*/


#include <complex>
#include <string>
#include <iostream>

#include "valuation.h"

Point getPoint(std::string nums)
{
	static const std::complex<double>
	eigenarray[3] = { {-0.412, 0.61}, {0.223, -1.12}, 1 };

	int numCount[3] = {0, 0, 0};
	for (int i = 0; i < static_cast<int>(nums.length()); ++i)
	{
		int index = static_cast<int>(nums.at(i)) - 48 - 1;
		numCount[index]++;
	}

	std::complex<double> sum = 0;
	for (int i = 0; i < 3; ++i)
	{
		sum += static_cast<double>(numCount[i]) * eigenarray[i];
		//std::cout << "  " << sum << " from " << eigenarray[i] << std::endl;
	}

	Point result;
	result.x = sum.real();
	result.y = sum.imag();
	return result;
}
#include "widget.h"
#include "ui_widget.h"
#include <iostream>

#include "valuation.h"
#include <QGridLayout>

// https://math.stackexchange.com/questions/1264647/what-method-is-used-for-projecting-the-rauzy-fractal ω

Widget::Widget(QWidget *parent) :
	QWidget(parent),
	ui(new Ui::Widget)
{
	ui->setupUi(this);

	showme = new QLabel;
	mymap = new QImage(400, 400, QImage::Format_ARGB32);
	mymap->fill(Qt::black);

	std::string trib = "12131211213121213121121312131211213121213121121312112131212131211213121312112131212131";
	for (int i = 0; i < trib.length(); ++i)
	{
		Point p = getPoint(trib.substr(i));
		std::cout << p.x << ", " << p.y << std::endl;

		int projX = qBound<int>(0, (p.x * 100) + 100, 400);
		int projY = qBound<int>(0, (p.y * 100) + 100, 400);
		std::cout << "[" << projX << ", " << projY << "]" << std::endl;

		if (trib.at(0) == '1')
			mymap->setPixel(projX, projY, Qt::red);

		if (trib.at(0) == '2')
			mymap->setPixel(projX, projY, Qt::green);

		if (trib.at(0) == '3')
			mymap->setPixel(projX, projY, Qt::blue);
	}

	showme->setPixmap(QPixmap::fromImage(*mymap));

	QGridLayout *lay = new QGridLayout;
	lay->addWidget(showme);
	setLayout(lay);
}

Widget::~Widget()
{
	delete ui;
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.