triangle group code reorganization
This commit is contained in:
		
							
								
								
									
										18
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
HEADERS=triangle.h linalg.h queue.h initcairo.h
 | 
			
		||||
HEADERS=triangle.h linalg.h queue.h initcairo.h main.h
 | 
			
		||||
 | 
			
		||||
#SPECIAL_OPTIONS=-O0 -g -D_DEBUG
 | 
			
		||||
SPECIAL_OPTIONS=-O0 -g -D_DEBUG
 | 
			
		||||
#SPECIAL_OPTIONS=-O3 -pg -funroll-loops -fno-inline
 | 
			
		||||
SPECIAL_OPTIONS=-O3 -flto -funroll-loops -Winline -Wall -Wno-unused-function -Werror=implicit-function-declaration
 | 
			
		||||
#SPECIAL_OPTIONS=-O3 -flto -funroll-loops -Winline -Wall -Wno-unused-function -Werror=implicit-function-declaration
 | 
			
		||||
#SPECIAL_OPTIONS=
 | 
			
		||||
 | 
			
		||||
CAIRO_OPTIONS=$(shell pkg-config --cflags cairo)
 | 
			
		||||
@@ -11,8 +11,8 @@ OPTIONS=$(GENERAL_OPTIONS) $(CAIRO_OPTIONS) $(SPECIAL_OPTIONS)
 | 
			
		||||
 | 
			
		||||
all: limit_set
 | 
			
		||||
 | 
			
		||||
limit_set: limit_set.o linalg.o triangle.o initcairo.o
 | 
			
		||||
	gcc $(OPTIONS) -o limit_set limit_set.o linalg.o triangle.o initcairo.o -lm -lgsl -lcblas -lcairo -lX11
 | 
			
		||||
limit_set: limit_set.o linalg.o triangle.o initcairo.o draw.o main.o
 | 
			
		||||
	gcc $(OPTIONS) -o limit_set limit_set.o linalg.o triangle.o initcairo.o draw.o main.o -lm -lgsl -lcblas -lcairo -lX11
 | 
			
		||||
 | 
			
		||||
linalg.o: linalg.c $(HEADERS)
 | 
			
		||||
	gcc $(OPTIONS) -c linalg.c
 | 
			
		||||
@@ -26,5 +26,11 @@ limit_set.o: limit_set.c $(HEADERS)
 | 
			
		||||
initcairo.o: initcairo.c $(HEADERS)
 | 
			
		||||
	gcc $(OPTIONS) -c initcairo.c
 | 
			
		||||
 | 
			
		||||
draw.o: draw.c $(HEADERS)
 | 
			
		||||
	gcc $(OPTIONS) -c draw.c
 | 
			
		||||
 | 
			
		||||
main.o: main.c $(HEADERS)
 | 
			
		||||
	gcc $(OPTIONS) -c main.c
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f limit_set linalg.o triangle.o limit_set.o
 | 
			
		||||
	rm -f limit_set linalg.o triangle.o limit_set.o draw.o main.o
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										407
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,407 @@
 | 
			
		||||
#include "main.h"
 | 
			
		||||
 | 
			
		||||
// level 0: helper functions
 | 
			
		||||
 | 
			
		||||
vector_t cross(vector_t a, vector_t b)
 | 
			
		||||
{
 | 
			
		||||
	vector_t result;
 | 
			
		||||
	result.x[0] = a.x[1]*b.x[2] - a.x[2]*b.x[1];
 | 
			
		||||
	result.x[1] = a.x[2]*b.x[0] - a.x[0]*b.x[2];
 | 
			
		||||
	result.x[2] = a.x[0]*b.x[1] - a.x[1]*b.x[0];
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector_t apply(DrawingContext *ctx, gsl_matrix *m, vector_t x)
 | 
			
		||||
{
 | 
			
		||||
	gsl_vector *tmp = getTempVector(ctx);
 | 
			
		||||
	gsl_vector *tmp2 = getTempVector(ctx);
 | 
			
		||||
	vector_t out;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) gsl_vector_set(tmp, i, x.x[i]);
 | 
			
		||||
	gsl_blas_dgemv(CblasNoTrans, 1.0, m, tmp, 0.0, tmp2);
 | 
			
		||||
	LOOP(i) out.x[i] = gsl_vector_get(tmp2, i);
 | 
			
		||||
 | 
			
		||||
	releaseTempVectors(ctx, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out)
 | 
			
		||||
{
 | 
			
		||||
	gsl_matrix *tmp = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *ev = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix **gen = getTempMatrices(ctx, 3);
 | 
			
		||||
 | 
			
		||||
	initializeTriangleGenerators(gen, ctx->cartan);
 | 
			
		||||
 | 
			
		||||
	gsl_matrix_set_identity(tmp);
 | 
			
		||||
	for(int i = 0; i < strlen(word); i++) {
 | 
			
		||||
		if(word[i] == ' ')
 | 
			
		||||
			continue;
 | 
			
		||||
		multiply_right(tmp, gen[word[i]-'a'], ctx->ws);
 | 
			
		||||
	}
 | 
			
		||||
	int count = real_eigenvectors(tmp, ev, ctx->ws);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) out[i].x[j] = gsl_matrix_get(ev, j, i);
 | 
			
		||||
 | 
			
		||||
	releaseTempMatrices(ctx, 5);
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void transformFrameStd(DrawingContext *ctx, vector_t *x, gsl_matrix *out)
 | 
			
		||||
{
 | 
			
		||||
	gsl_matrix *tmp = getTempMatrix(ctx);
 | 
			
		||||
	gsl_vector *fourth = getTempVector(ctx);
 | 
			
		||||
	gsl_vector *lambda = getTempVector(ctx);
 | 
			
		||||
	int s;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) gsl_matrix_set(out, j, i, x[i].x[j]);
 | 
			
		||||
	gsl_matrix_memcpy(tmp, out);
 | 
			
		||||
	gsl_linalg_LU_decomp(tmp, ctx->ws->permutation, &s);
 | 
			
		||||
	gsl_linalg_LU_solve(tmp, ctx->ws->permutation, fourth, lambda);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) *gsl_matrix_ptr(out, i, j) *= gsl_vector_get(lambda, j);
 | 
			
		||||
 | 
			
		||||
	gsl_matrix_fprintf(stdout, out, "%f");
 | 
			
		||||
 | 
			
		||||
	releaseTempMatrices(ctx, 1);
 | 
			
		||||
	releaseTempVectors(ctx, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// level 1: the elementary drawing functions, drawPoint, drawSegment2d
 | 
			
		||||
 | 
			
		||||
void drawPoint(DrawingContext *ctx, point_t p)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	cairo_save(C);
 | 
			
		||||
	cairo_move_to(C, p.x, p.y);
 | 
			
		||||
	cairo_close_path(C);
 | 
			
		||||
	cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
	cairo_set_line_width(C, 10.0/ctx->dim->scalefactor);
 | 
			
		||||
	cairo_stroke(C);
 | 
			
		||||
	cairo_restore(C);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawSegment2d(DrawingContext *ctx, point_t a, point_t b)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
	cairo_move_to(C, a.x, a.y);
 | 
			
		||||
	cairo_line_to(C, b.x, b.y);
 | 
			
		||||
	cairo_stroke(C);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// level 2: drawVector, drawCovector, drawSegment
 | 
			
		||||
 | 
			
		||||
static point_t vectorToPoint(DrawingContext *ctx, vector_t in)
 | 
			
		||||
{
 | 
			
		||||
	double x[3];
 | 
			
		||||
	point_t out;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) x[i] = 0.0;
 | 
			
		||||
	LOOP(i) LOOP(j) x[i] += gsl_matrix_get(ctx->cob, i, j) * in.x[j];
 | 
			
		||||
 | 
			
		||||
	out.x = x[0] / x[2];
 | 
			
		||||
	out.y = x[1] / x[2];
 | 
			
		||||
 | 
			
		||||
	return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawVector(DrawingContext *ctx, vector_t v)
 | 
			
		||||
{
 | 
			
		||||
	drawPoint(ctx, vectorToPoint(ctx, v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drawImplicitLine(DrawingContext *ctx, double a, double b, double c)
 | 
			
		||||
{
 | 
			
		||||
	double norm, lambda;
 | 
			
		||||
	point_t m, s, xminus, xplus;
 | 
			
		||||
	m.x = ctx->dim->center_x;
 | 
			
		||||
	m.y = ctx->dim->center_y;
 | 
			
		||||
	lambda = (a*m.x + b*m.y + c)/(a*a + b*b);
 | 
			
		||||
	s.x = m.x - lambda*a;
 | 
			
		||||
	s.y = m.y - lambda*b;
 | 
			
		||||
	norm = sqrt(a*a + b*b);
 | 
			
		||||
	xminus.x = s.x - ctx->dim->radius * b / norm;
 | 
			
		||||
	xminus.y = s.y + ctx->dim->radius * a / norm;
 | 
			
		||||
	xplus.x = s.x + ctx->dim->radius * b / norm;
 | 
			
		||||
	xplus.y = s.y - ctx->dim->radius * a / norm;
 | 
			
		||||
 | 
			
		||||
	drawSegment2d(ctx, xminus, xplus);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawCovector(DrawingContext *ctx, vector_t v)
 | 
			
		||||
{
 | 
			
		||||
	double x[3];
 | 
			
		||||
	double cofactor;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) x[i] = 0.0;
 | 
			
		||||
	LOOP(i) LOOP(j) {
 | 
			
		||||
		cofactor = gsl_matrix_get(ctx->cob, (i+1)%3, (j+1)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+2)%3)
 | 
			
		||||
			- gsl_matrix_get(ctx->cob, (i+1)%3, (j+2)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+1)%3);
 | 
			
		||||
		x[i] += cofactor * v.x[j];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drawImplicitLine(ctx, x[0], x[1], x[2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawSegment(DrawingContext *ctx, vector_t a, vector_t b)
 | 
			
		||||
{
 | 
			
		||||
	drawSegment2d(ctx, vectorToPoint(ctx, a), vectorToPoint(ctx, b));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// level 3: boxes and polygons
 | 
			
		||||
 | 
			
		||||
void drawPolygon(DrawingContext *ctx, int sides, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list args;
 | 
			
		||||
	vector_t first, prev, current;
 | 
			
		||||
 | 
			
		||||
	va_start(args, sides);
 | 
			
		||||
 | 
			
		||||
	first = va_arg(args, vector_t);
 | 
			
		||||
	current = first;
 | 
			
		||||
	for(int i = 0; i < sides-1; i++) {
 | 
			
		||||
		prev = current;
 | 
			
		||||
		current = va_arg(args, vector_t);
 | 
			
		||||
		drawSegment(ctx, prev, current);
 | 
			
		||||
	}
 | 
			
		||||
	drawSegment(ctx, current, first);
 | 
			
		||||
 | 
			
		||||
	va_end(args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawTriangle(DrawingContext *ctx, const char *word)
 | 
			
		||||
{
 | 
			
		||||
	vector_t p[3];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(ctx, word, p);
 | 
			
		||||
	drawPolygon(ctx, 3, p[0], p[1], p[2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBox(DrawingContext *ctx, const char *word1, const char *word2)
 | 
			
		||||
{
 | 
			
		||||
	vector_t p[2][3],i[2];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(ctx, word1, p[0]);
 | 
			
		||||
	fixedPoints(ctx, word2, p[1]);
 | 
			
		||||
 | 
			
		||||
	// intersect attracting line with neutral line of the other element
 | 
			
		||||
	for(int j = 0; j < 2; j++)
 | 
			
		||||
		i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
 | 
			
		||||
 | 
			
		||||
	drawPolygon(ctx, 4, p[0][0], i[0], p[1][0], i[1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBoxStd(DrawingContext *ctx, const char *word, char base)
 | 
			
		||||
{
 | 
			
		||||
	char word1[100];
 | 
			
		||||
	char word2[100];
 | 
			
		||||
 | 
			
		||||
	int len = strlen(word);
 | 
			
		||||
	if(len*2 + 4 > 100)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < len; i++) {
 | 
			
		||||
		word1[i] = word1[2*len+2-i] = word[i];
 | 
			
		||||
		word2[i] = word2[2*len+2-i] = word[i];
 | 
			
		||||
	}
 | 
			
		||||
	word1[2*len+3] = 0;
 | 
			
		||||
	word2[2*len+3] = 0;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) word1[len+i] = (base-'A'+6+i+1)%3+'a';
 | 
			
		||||
	LOOP(i) word2[len+i] = (base-'A'+6-i-1)%3+'a';
 | 
			
		||||
 | 
			
		||||
//	printf("Words: %s %s\n", word1, word2);
 | 
			
		||||
 | 
			
		||||
	drawBox(ctx, word1, word2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// level 4: draw the actual image components
 | 
			
		||||
 | 
			
		||||
void drawReflectors(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	vector_t v[3];
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) { v[i].x[j] = (i==j) ? 1.0 : 0.0; }
 | 
			
		||||
	LOOP(i) drawVector(ctx, v[i]);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
 | 
			
		||||
	LOOP(i) drawCovector(ctx, v[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawAttractors(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	vector_t p[3][3];
 | 
			
		||||
	vector_t l[3][3];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(ctx, "abc", p[0]);
 | 
			
		||||
	fixedPoints(ctx, "bca", p[1]);
 | 
			
		||||
	fixedPoints(ctx, "cab", p[2]);
 | 
			
		||||
 | 
			
		||||
	double color[3][3] = {{1,0,0},{0,0.7,0},{0,0,1}};
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) {
 | 
			
		||||
		cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
 | 
			
		||||
		drawVector(ctx, p[i][j]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) {
 | 
			
		||||
		cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
 | 
			
		||||
		drawCovector(ctx, l[i][j]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBoxes(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 0);
 | 
			
		||||
	drawTriangle(ctx, "abc");
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 1);
 | 
			
		||||
	drawTriangle(ctx, "aca abc aca");
 | 
			
		||||
	drawTriangle(ctx, "acac abc caca");
 | 
			
		||||
	drawTriangle(ctx, "acaca abc acaca");
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0.8, 0);
 | 
			
		||||
	drawTriangle(ctx, "cac abc cac");
 | 
			
		||||
	drawTriangle(ctx, "caca abc acac");
 | 
			
		||||
	drawTriangle(ctx, "cacac abc cacac");
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 0);
 | 
			
		||||
	drawBoxStd(ctx, "c", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "a", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "b", 'B');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 0);
 | 
			
		||||
	drawBoxStd(ctx, "ca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cac", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "acac", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "ac", 'C');
 | 
			
		||||
 | 
			
		||||
	drawBoxStd(ctx, "aca cb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca bc", 'C');
 | 
			
		||||
 | 
			
		||||
	drawBoxStd(ctx, "caca cb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca bc", 'C');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 1);
 | 
			
		||||
	drawBoxStd(ctx, "ca bc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "ca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "ca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca cb", 'B');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 1, 0);
 | 
			
		||||
//	drawBoxStd(ctx, "ca bc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "cabc ba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc bab", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "cabc baba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc abab", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "cabc aba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc ab", 'B');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawLimitCurve(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	cairo_save(C);
 | 
			
		||||
 | 
			
		||||
	int previous_inside = 0;
 | 
			
		||||
	for(int i = 0; i < ctx->n_group_elements; i++) {
 | 
			
		||||
		double x = ctx->limit_curve[3*i];
 | 
			
		||||
		double y = ctx->limit_curve[3*i+1];
 | 
			
		||||
 | 
			
		||||
		cairo_user_to_device(C, &x, &y);
 | 
			
		||||
 | 
			
		||||
		if(-x < ctx->dim->width && x < 3*ctx->dim->width && -y < ctx->dim->height && y < 3*ctx->dim->height) {
 | 
			
		||||
			if(ctx->limit_with_lines) {
 | 
			
		||||
				if(!previous_inside)
 | 
			
		||||
					cairo_move_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
 | 
			
		||||
				else
 | 
			
		||||
					cairo_line_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
 | 
			
		||||
			} else {
 | 
			
		||||
				cairo_move_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
 | 
			
		||||
				cairo_close_path(C);
 | 
			
		||||
			}
 | 
			
		||||
			previous_inside = 1;
 | 
			
		||||
		} else {
 | 
			
		||||
			previous_inside = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(!ctx->limit_with_lines) { // draw dots instead of lines
 | 
			
		||||
		cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
		cairo_set_line_width(C, 3.0/ctx->dim->scalefactor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 0);
 | 
			
		||||
	cairo_stroke(C);
 | 
			
		||||
 | 
			
		||||
	cairo_restore(C);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawText(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_move_to(ctx->cairo, 15, 30);
 | 
			
		||||
	cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
 | 
			
		||||
	char buf[100];
 | 
			
		||||
	sprintf(buf, "t = exp(%.8f) = %.8f", log(ctx->parameter), ctx->parameter);
 | 
			
		||||
	cairo_show_text(ctx->cairo, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// level 5: put everything together
 | 
			
		||||
 | 
			
		||||
void draw(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 1, 1);
 | 
			
		||||
	cairo_paint(C);
 | 
			
		||||
 | 
			
		||||
	cairo_set_matrix(C, &ctx->dim->matrix);
 | 
			
		||||
 | 
			
		||||
	// defaults; use save/restore whenever these are changed
 | 
			
		||||
	cairo_set_line_width(C, 1.0/ctx->dim->scalefactor);
 | 
			
		||||
	cairo_set_font_size(C, 16);
 | 
			
		||||
	cairo_set_line_join(C, CAIRO_LINE_JOIN_BEVEL);
 | 
			
		||||
	cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
 | 
			
		||||
	if(ctx->limit_curve_valid) {
 | 
			
		||||
		if(ctx->show_limit)
 | 
			
		||||
			drawLimitCurve(ctx);
 | 
			
		||||
 | 
			
		||||
		if(ctx->show_boxes)
 | 
			
		||||
			drawBoxes(ctx);
 | 
			
		||||
 | 
			
		||||
		if(ctx->show_attractors)
 | 
			
		||||
			drawAttractors(ctx);
 | 
			
		||||
 | 
			
		||||
		if(ctx->show_reflectors)
 | 
			
		||||
			drawReflectors(ctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cairo_identity_matrix(C); // text is in screen coordinates
 | 
			
		||||
 | 
			
		||||
	drawText(ctx);
 | 
			
		||||
 | 
			
		||||
	cairo_surface_flush(cairo_get_target(C));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								initcairo.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								initcairo.c
									
									
									
									
									
								
							@@ -12,28 +12,11 @@ static Bool alwaysTruePredicate(Display *display, XEvent *event, XPointer arg)
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this computes center, radius and scalefactor out of ctx->matrix
 | 
			
		||||
void updateDimensions(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	double det = ctx->matrix.xx * ctx->matrix.yy - ctx->matrix.xy * ctx->matrix.yx;
 | 
			
		||||
	double cx = (double)ctx->width/2;
 | 
			
		||||
	double cy = (double)ctx->height/2;
 | 
			
		||||
	double r = 2*sqrt((cx*cx + cy*cy)/det); // this is not safe anymore if we have non-uniform scaling
 | 
			
		||||
 | 
			
		||||
	// don't use cairo_device_to_user() since the matrix might not be our CTM yet
 | 
			
		||||
	cx -= ctx->matrix.x0;
 | 
			
		||||
	cy -= ctx->matrix.y0;
 | 
			
		||||
	ctx->center_x = (  ctx->matrix.yy * cx - ctx->matrix.xy * cy) / det;
 | 
			
		||||
	ctx->center_y = (- ctx->matrix.yx * cx + ctx->matrix.xx * cy) / det;
 | 
			
		||||
	ctx->radius = r;
 | 
			
		||||
	ctx->scalefactor = sqrt(det);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	GraphicsInfo *info = malloc(sizeof(GraphicsInfo));
 | 
			
		||||
	DrawingContext *ctx = malloc(sizeof(DrawingContext));
 | 
			
		||||
	info->context = ctx;
 | 
			
		||||
	DimensionsInfo *dim = malloc(sizeof(DimensionsInfo));
 | 
			
		||||
	info->dim = dim;
 | 
			
		||||
 | 
			
		||||
	mask |= StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask | PointerMotionMask;
 | 
			
		||||
 | 
			
		||||
@@ -65,10 +48,11 @@ GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char
 | 
			
		||||
	int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
 | 
			
		||||
	info->buffer = malloc(stride*height);
 | 
			
		||||
	info->buffer_surface = cairo_image_surface_create_for_data(info->buffer, CAIRO_FORMAT_ARGB32, width, height, stride);
 | 
			
		||||
	info->context->cairo = cairo_create(info->buffer_surface);
 | 
			
		||||
	cairo_matrix_init_identity(&info->context->matrix);
 | 
			
		||||
	info->context->width = width;
 | 
			
		||||
	info->context->height = height;
 | 
			
		||||
	info->buffer_context = cairo_create(info->buffer_surface);
 | 
			
		||||
	cairo_matrix_init_identity(&info->dim->matrix);
 | 
			
		||||
	info->dim->width = width;
 | 
			
		||||
	info->dim->height = height;
 | 
			
		||||
	updateDimensions(info->dim);
 | 
			
		||||
 | 
			
		||||
	info->wm_delete_window = XInternAtom(info->display, "WM_DELETE_WINDOW", 0);
 | 
			
		||||
	info->wm_protocols = XInternAtom(info->display, "WM_PROTOCOLS", 0);
 | 
			
		||||
@@ -81,7 +65,7 @@ GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char
 | 
			
		||||
 | 
			
		||||
void destroyCairo(GraphicsInfo *info)
 | 
			
		||||
{
 | 
			
		||||
	cairo_destroy(info->context->cairo);
 | 
			
		||||
	cairo_destroy(info->buffer_context);
 | 
			
		||||
	cairo_destroy(info->front_context);
 | 
			
		||||
	cairo_surface_destroy(info->surface);
 | 
			
		||||
	cairo_surface_destroy(info->buffer_surface);
 | 
			
		||||
@@ -89,7 +73,7 @@ void destroyCairo(GraphicsInfo *info)
 | 
			
		||||
	XDestroyWindow(info->display, info->win);
 | 
			
		||||
	XFreeColormap(info->display, info->cmap);
 | 
			
		||||
	XCloseDisplay(info->display);
 | 
			
		||||
	free(info->context);
 | 
			
		||||
	free(info->dim);
 | 
			
		||||
	free(info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -119,7 +103,7 @@ void waitUpdateTimer(GraphicsInfo *info)
 | 
			
		||||
	info->frames++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingContext *))
 | 
			
		||||
int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(void *))
 | 
			
		||||
{
 | 
			
		||||
	int state;
 | 
			
		||||
	static int last_x, last_y;
 | 
			
		||||
@@ -133,17 +117,18 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
 | 
			
		||||
	case ConfigureNotify:
 | 
			
		||||
		printf("ConfigureNotify Event, new dimensions: %d %d %d %d\n", ev->xconfigure.x, ev->xconfigure.y, ev->xconfigure.width, ev->xconfigure.height);
 | 
			
		||||
		info->context->width = ev->xconfigure.width;
 | 
			
		||||
		info->context->height = ev->xconfigure.height;
 | 
			
		||||
		cairo_xlib_surface_set_size(info->surface, info->context->width, info->context->height);
 | 
			
		||||
		info->dim->width = ev->xconfigure.width;
 | 
			
		||||
		info->dim->height = ev->xconfigure.height;
 | 
			
		||||
		updateDimensions(info->dim);
 | 
			
		||||
		cairo_xlib_surface_set_size(info->surface, info->dim->width, info->dim->height);
 | 
			
		||||
 | 
			
		||||
		cairo_destroy(info->context->cairo);
 | 
			
		||||
		cairo_destroy(info->buffer_context);
 | 
			
		||||
		cairo_surface_destroy(info->buffer_surface);
 | 
			
		||||
		free(info->buffer);
 | 
			
		||||
		stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, info->context->width);
 | 
			
		||||
		info->buffer = malloc(stride*info->context->height);
 | 
			
		||||
		info->buffer_surface = cairo_image_surface_create_for_data(info->buffer, CAIRO_FORMAT_ARGB32, info->context->width, info->context->height, stride);
 | 
			
		||||
		info->context->cairo = cairo_create(info->buffer_surface);
 | 
			
		||||
		stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, info->dim->width);
 | 
			
		||||
		info->buffer = malloc(stride*info->dim->height);
 | 
			
		||||
		info->buffer_surface = cairo_image_surface_create_for_data(info->buffer, CAIRO_FORMAT_ARGB32, info->dim->width, info->dim->height, stride);
 | 
			
		||||
		info->buffer_context = cairo_create(info->buffer_surface);
 | 
			
		||||
 | 
			
		||||
		return STATUS_REDRAW;
 | 
			
		||||
 | 
			
		||||
@@ -160,7 +145,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
			cairo_matrix_translate(&transform, ev->xbutton.x, ev->xbutton.y);
 | 
			
		||||
			cairo_matrix_scale(&transform, 5.0/4.0, 5.0/4.0);
 | 
			
		||||
			cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
 | 
			
		||||
			cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
 | 
			
		||||
			cairo_matrix_multiply(&info->dim->matrix, &info->dim->matrix, &transform);
 | 
			
		||||
			status = STATUS_REDRAW;
 | 
			
		||||
		} else if(ev->xbutton.button == 5) {
 | 
			
		||||
			cairo_matrix_t transform;
 | 
			
		||||
@@ -168,12 +153,13 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
			cairo_matrix_translate(&transform, ev->xbutton.x, ev->xbutton.y);
 | 
			
		||||
			cairo_matrix_scale(&transform, 4.0/5.0, 4.0/5.0);
 | 
			
		||||
			cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
 | 
			
		||||
			cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
 | 
			
		||||
			cairo_matrix_multiply(&info->dim->matrix, &info->dim->matrix, &transform);
 | 
			
		||||
			status = STATUS_REDRAW;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		last_x = ev->xbutton.x;
 | 
			
		||||
		last_y = ev->xbutton.y;
 | 
			
		||||
		updateDimensions(info->dim);
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	case MotionNotify:
 | 
			
		||||
@@ -184,7 +170,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
			cairo_matrix_t transform;
 | 
			
		||||
			cairo_matrix_init_identity(&transform);
 | 
			
		||||
			cairo_matrix_translate(&transform, dx, dy);
 | 
			
		||||
			cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
 | 
			
		||||
			cairo_matrix_multiply(&info->dim->matrix, &info->dim->matrix, &transform);
 | 
			
		||||
			status = STATUS_REDRAW;
 | 
			
		||||
		} else if(ev->xmotion.state & Button1Mask && ev->xmotion.state & ShiftMask) {
 | 
			
		||||
			double width = (double) cairo_xlib_surface_get_width(info->surface);
 | 
			
		||||
@@ -199,7 +185,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
			cairo_matrix_translate(&transform, width/2, height/2);
 | 
			
		||||
			cairo_matrix_rotate(&transform, angle);
 | 
			
		||||
			cairo_matrix_translate(&transform, -width/2, -height/2);
 | 
			
		||||
			cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
 | 
			
		||||
			cairo_matrix_multiply(&info->dim->matrix, &info->dim->matrix, &transform);
 | 
			
		||||
			status = STATUS_REDRAW;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -219,7 +205,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
 | 
			
		||||
	return STATUS_NOTHING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(DrawingContext*)) // get any events from the queue and the server, process them if neccessary, quit if wanted
 | 
			
		||||
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(void *)) // get any events from the queue and the server, process them if neccessary, quit if wanted
 | 
			
		||||
{
 | 
			
		||||
	XEvent ev;
 | 
			
		||||
	int x11_fd;
 | 
			
		||||
@@ -264,3 +250,20 @@ int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this computes center, radius and scalefactor out of ctx->matrix
 | 
			
		||||
void updateDimensions(DimensionsInfo *dim)
 | 
			
		||||
{
 | 
			
		||||
	double det = dim->matrix.xx * dim->matrix.yy - dim->matrix.xy * dim->matrix.yx;
 | 
			
		||||
	double cx = (double)dim->width/2;
 | 
			
		||||
	double cy = (double)dim->height/2;
 | 
			
		||||
	double r = 2*sqrt((cx*cx + cy*cy)/det); // this is not safe anymore if we have non-uniform scaling
 | 
			
		||||
 | 
			
		||||
	// don't use cairo_device_to_user() since the matrix might not be our CTM yet
 | 
			
		||||
	cx -= dim->matrix.x0;
 | 
			
		||||
	cy -= dim->matrix.y0;
 | 
			
		||||
	dim->center_x = (  dim->matrix.yy * cx - dim->matrix.xy * cy) / det;
 | 
			
		||||
	dim->center_y = (- dim->matrix.yx * cx + dim->matrix.xx * cy) / det;
 | 
			
		||||
	dim->radius = r;
 | 
			
		||||
	dim->scalefactor = sqrt(det);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								initcairo.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								initcairo.h
									
									
									
									
									
								
							@@ -17,7 +17,6 @@
 | 
			
		||||
#define STATUS_QUIT 2
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	cairo_t *cairo;
 | 
			
		||||
	cairo_matrix_t matrix;
 | 
			
		||||
	unsigned int width;
 | 
			
		||||
	unsigned int height;
 | 
			
		||||
@@ -27,10 +26,9 @@ typedef struct {
 | 
			
		||||
	double center_x;
 | 
			
		||||
	double center_y;
 | 
			
		||||
	double radius;
 | 
			
		||||
} DrawingContext;
 | 
			
		||||
} DimensionsInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	DrawingContext *context;
 | 
			
		||||
	Display *display;
 | 
			
		||||
	Window win;
 | 
			
		||||
	Colormap cmap;
 | 
			
		||||
@@ -40,11 +38,13 @@ typedef struct {
 | 
			
		||||
	cairo_t *front_context;
 | 
			
		||||
 | 
			
		||||
	cairo_surface_t *buffer_surface;
 | 
			
		||||
	cairo_t *buffer_context;
 | 
			
		||||
	unsigned char *buffer;
 | 
			
		||||
 | 
			
		||||
	struct timeval start_time;
 | 
			
		||||
	unsigned long frames;
 | 
			
		||||
	double elapsed, frametime;
 | 
			
		||||
	DimensionsInfo *dim;
 | 
			
		||||
} GraphicsInfo;
 | 
			
		||||
 | 
			
		||||
GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char *name);
 | 
			
		||||
@@ -52,7 +52,7 @@ void destroyCairo(GraphicsInfo *info);
 | 
			
		||||
 | 
			
		||||
void startTimer(GraphicsInfo *info);
 | 
			
		||||
void waitUpdateTimer(GraphicsInfo *info);
 | 
			
		||||
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(DrawingContext *));
 | 
			
		||||
void updateDimensions(DrawingContext *ctx);
 | 
			
		||||
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(void *));
 | 
			
		||||
void updateDimensions(DimensionsInfo *ctx);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										711
									
								
								limit_set.c
									
									
									
									
									
								
							
							
						
						
									
										711
									
								
								limit_set.c
									
									
									
									
									
								
							@@ -1,59 +1,9 @@
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <cairo/cairo-pdf.h>
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
#include "main.h"
 | 
			
		||||
 | 
			
		||||
#include "initcairo.h"
 | 
			
		||||
#include "triangle.h"
 | 
			
		||||
#include "linalg.h"
 | 
			
		||||
 | 
			
		||||
#define LOOP(i) for(int i = 0; i < 3; i++)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	double x;
 | 
			
		||||
	double y;
 | 
			
		||||
} point_t;
 | 
			
		||||
 | 
			
		||||
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s);
 | 
			
		||||
void initializeTriangleGenerators(gsl_matrix **gen, gsl_matrix *cartan);
 | 
			
		||||
point_t intersect(point_t a, point_t b, point_t c, point_t d);
 | 
			
		||||
void drawPoint(DrawingContext *ctx, point_t p);
 | 
			
		||||
void drawSegment(DrawingContext *ctx, point_t a, point_t b);
 | 
			
		||||
void drawLine(DrawingContext *ctx, point_t a, point_t b);
 | 
			
		||||
void drawImplicitLine(DrawingContext *ctx, double a, double b, double c);
 | 
			
		||||
void drawPolygon(DrawingContext *ctx, int sides, ...);
 | 
			
		||||
void drawAttractorConnection(DrawingContext *ctx, const char *word1, const char *word2);
 | 
			
		||||
void drawBox(DrawingContext *ctx, const char *word1, const char *word2);
 | 
			
		||||
void drawBoxStd(DrawingContext *ctx, const char *word, char base);
 | 
			
		||||
int compareAngle(const void *x, const void *y);
 | 
			
		||||
int computeLimitCurve();
 | 
			
		||||
void drawBoxes(DrawingContext *ctx);
 | 
			
		||||
void drawReflectors(DrawingContext *ctx);
 | 
			
		||||
void drawAttractors(DrawingContext *ctx);
 | 
			
		||||
void draw(DrawingContext *ctx);
 | 
			
		||||
void setup();
 | 
			
		||||
void destroy();
 | 
			
		||||
void print(DrawingContext *screen);
 | 
			
		||||
int processEvent(GraphicsInfo *info, XEvent *ev);
 | 
			
		||||
 | 
			
		||||
double parameter;
 | 
			
		||||
int n_group_elements;
 | 
			
		||||
double *limit_curve; // x, y, angle triples
 | 
			
		||||
int limit_curve_valid = 0;
 | 
			
		||||
groupelement_t *group;
 | 
			
		||||
workspace_t *ws;
 | 
			
		||||
gsl_matrix *gen[3];
 | 
			
		||||
gsl_matrix **matrices;
 | 
			
		||||
gsl_matrix *cartan, *cob, *coxeter, *coxeter_fixedpoints, *fixedpoints;
 | 
			
		||||
 | 
			
		||||
int show_boxes = 0;
 | 
			
		||||
int show_attractors = 0;
 | 
			
		||||
int show_reflectors = 0;
 | 
			
		||||
int show_limit = 1;
 | 
			
		||||
int limit_with_lines = 1;
 | 
			
		||||
int use_repelling = 1;
 | 
			
		||||
static int compareAngle(const void *x, const void *y)
 | 
			
		||||
{
 | 
			
		||||
	return ((double*)x)[2] > ((double*)y)[2] ? 1 : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s)
 | 
			
		||||
{
 | 
			
		||||
@@ -76,622 +26,73 @@ void initializeTriangleGenerators(gsl_matrix **gen, gsl_matrix *cartan)
 | 
			
		||||
	LOOP(i) LOOP(j) *gsl_matrix_ptr(gen[i], i, j) += gsl_matrix_get(cartan, i, j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// intersect the lines a-b and c-d
 | 
			
		||||
point_t intersect(point_t a, point_t b, point_t c, point_t d)
 | 
			
		||||
int computeLimitCurve(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	point_t res;
 | 
			
		||||
	double t = ((c.y-d.y)*(c.x-a.x) - (c.x-d.x)*(c.y-a.y)) / ((b.x-a.x)*(c.y-d.y) - (b.y-a.y)*(c.x-d.x));
 | 
			
		||||
	res.x = (1-t)*a.x + t*b.x;
 | 
			
		||||
	res.y = (1-t)*a.y + t*b.y;
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
	workspace_t *ws = ctx->ws;
 | 
			
		||||
	gsl_matrix *cartan_pos = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *cob_pos = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *coxeter_pos = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *coxeter_fixedpoints_pos = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *fixedpoints_pos = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *coxeter = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *coxeter_fixedpoints = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *fixedpoints = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix **gen = getTempMatrices(ctx, 3);
 | 
			
		||||
	gsl_matrix **elements = getTempMatrices(ctx, ctx->n_group_elements);
 | 
			
		||||
	groupelement_t *group = ctx->group;
 | 
			
		||||
	int success = 0;
 | 
			
		||||
 | 
			
		||||
void drawPoint(DrawingContext *ctx, point_t p)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
	int column = ctx->use_repelling ? 2 : 0;
 | 
			
		||||
	ctx->limit_curve_valid = 0;
 | 
			
		||||
 | 
			
		||||
	cairo_save(C);
 | 
			
		||||
	cairo_move_to(C, p.x, p.y);
 | 
			
		||||
	cairo_close_path(C);
 | 
			
		||||
	cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
	cairo_set_line_width(C, 10.0/ctx->scalefactor);
 | 
			
		||||
	cairo_stroke(C);
 | 
			
		||||
	cairo_restore(C);
 | 
			
		||||
}
 | 
			
		||||
	// do first in the Fuchsian positive case to get the angles
 | 
			
		||||
	cartanMatrix(cartan_pos, M_PI/ctx->p[0], M_PI/ctx->p[1], M_PI/ctx->p[2], 1.0);
 | 
			
		||||
	initializeTriangleGenerators(gen, cartan_pos);
 | 
			
		||||
	gsl_matrix_set_identity(elements[0]);
 | 
			
		||||
	for(int i = 1; i < ctx->n_group_elements; i++)
 | 
			
		||||
		multiply(elements[group[i].parent->id], gen[group[i].letter], elements[i]);
 | 
			
		||||
	diagonalize_symmetric_form(cartan_pos, cob_pos, ws);
 | 
			
		||||
	multiply_many(ws, coxeter_pos, 3, gen[0], gen[1], gen[2]);
 | 
			
		||||
	int ev_count_pos = real_eigenvectors(coxeter_pos, coxeter_fixedpoints_pos, ws);
 | 
			
		||||
 | 
			
		||||
void drawSegment(DrawingContext *ctx, point_t a, point_t b)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
	cairo_move_to(C, a.x, a.y);
 | 
			
		||||
	cairo_line_to(C, b.x, b.y);
 | 
			
		||||
	cairo_stroke(C);
 | 
			
		||||
}
 | 
			
		||||
	if(ev_count_pos != 3)
 | 
			
		||||
		goto error_out;
 | 
			
		||||
 | 
			
		||||
void drawLine(DrawingContext *ctx, point_t a, point_t b)
 | 
			
		||||
{
 | 
			
		||||
	// not implemented
 | 
			
		||||
	point_t c, xplus, xminus;
 | 
			
		||||
	double normb;
 | 
			
		||||
	double scalbc;
 | 
			
		||||
 | 
			
		||||
	c.x = ctx->center_x;
 | 
			
		||||
	c.y = ctx->center_y;
 | 
			
		||||
	b.x -= a.x;
 | 
			
		||||
	b.y -= a.y;
 | 
			
		||||
	c.x -= a.x;
 | 
			
		||||
	c.y -= a.y;
 | 
			
		||||
	normb = sqrt(b.x*b.x + b.y*b.y);
 | 
			
		||||
	b.x /= normb;
 | 
			
		||||
	b.y /= normb;
 | 
			
		||||
	scalbc = b.x*c.x + b.y*c.y;
 | 
			
		||||
	xplus.x = a.x + (scalbc + ctx->radius)*b.x;
 | 
			
		||||
	xplus.y = a.y + (scalbc + ctx->radius)*b.y;
 | 
			
		||||
	xminus.x = a.x + (scalbc - ctx->radius)*b.x;
 | 
			
		||||
	xminus.y = a.y + (scalbc - ctx->radius)*b.y;
 | 
			
		||||
 | 
			
		||||
	drawSegment(ctx, xminus, xplus);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawImplicitLine(DrawingContext *ctx, double a, double b, double c)
 | 
			
		||||
{
 | 
			
		||||
	// not implemented
 | 
			
		||||
	double norm, lambda;
 | 
			
		||||
	point_t m, s, xminus, xplus;
 | 
			
		||||
	m.x = ctx->center_x;
 | 
			
		||||
	m.y = ctx->center_y;
 | 
			
		||||
	lambda = (a*m.x + b*m.y + c)/(a*a + b*b);
 | 
			
		||||
	s.x = m.x - lambda*a;
 | 
			
		||||
	s.y = m.y - lambda*b;
 | 
			
		||||
	norm = sqrt(a*a + b*b);
 | 
			
		||||
	xminus.x = s.x - ctx->radius * b / norm;
 | 
			
		||||
	xminus.y = s.y + ctx->radius * a / norm;
 | 
			
		||||
	xplus.x = s.x + ctx->radius * b / norm;
 | 
			
		||||
	xplus.y = s.y - ctx->radius * a / norm;
 | 
			
		||||
 | 
			
		||||
	drawSegment(ctx, xminus, xplus);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawPolygon(DrawingContext *ctx, int sides, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list args;
 | 
			
		||||
	point_t first, prev, current;
 | 
			
		||||
 | 
			
		||||
	va_start(args, sides);
 | 
			
		||||
 | 
			
		||||
	first = va_arg(args, point_t);
 | 
			
		||||
	current = first;
 | 
			
		||||
	for(int i = 0; i < sides-1; i++) {
 | 
			
		||||
		prev = current;
 | 
			
		||||
		current = va_arg(args, point_t);
 | 
			
		||||
		drawSegment(ctx, prev, current);
 | 
			
		||||
	}
 | 
			
		||||
	drawSegment(ctx, current, first);
 | 
			
		||||
 | 
			
		||||
	va_end(args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fixedPoints(const char *word, point_t *out)
 | 
			
		||||
{
 | 
			
		||||
	gsl_matrix *tmp = ws->stack[10];
 | 
			
		||||
	gsl_matrix *ev = ws->stack[11];
 | 
			
		||||
 | 
			
		||||
	gsl_matrix_set_identity(tmp);
 | 
			
		||||
	for(int i = 0; i < strlen(word); i++) {
 | 
			
		||||
		if(word[i] == ' ')
 | 
			
		||||
			continue;
 | 
			
		||||
		multiply_right(tmp, gen[word[i]-'a'], ws);
 | 
			
		||||
	}
 | 
			
		||||
	int count = real_eigenvectors(tmp, ev, ws);
 | 
			
		||||
	multiply_left(cob, ev, ws);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) out[i].x = gsl_matrix_get(ev, 0, i) / gsl_matrix_get(ev, 2, i);
 | 
			
		||||
	LOOP(i) out[i].y = gsl_matrix_get(ev, 1, i) / gsl_matrix_get(ev, 2, i);
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawAttractorConnection(DrawingContext *ctx, const char *word1, const char *word2)
 | 
			
		||||
{
 | 
			
		||||
	point_t p1[3], p2[3];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(word1, p1);
 | 
			
		||||
	fixedPoints(word2, p2);
 | 
			
		||||
 | 
			
		||||
	drawSegment(ctx, p1[0], p2[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawTriangle(DrawingContext *ctx, const char *word)
 | 
			
		||||
{
 | 
			
		||||
	point_t p[3];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(word, p);
 | 
			
		||||
	drawPolygon(ctx, 3, p[0], p[1], p[2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBox(DrawingContext *ctx, const char *word1, const char *word2)
 | 
			
		||||
{
 | 
			
		||||
	point_t p[2][3],i[2];
 | 
			
		||||
 | 
			
		||||
	fixedPoints(word1, p[0]);
 | 
			
		||||
	fixedPoints(word2, p[1]);
 | 
			
		||||
 | 
			
		||||
	// intersect attracting line with neutral line of the other element
 | 
			
		||||
	for(int j = 0; j < 2; j++)
 | 
			
		||||
		i[j] = intersect(p[j%2][0],p[j%2][1],p[(j+1)%2][0],p[(j+1)%2][2]);
 | 
			
		||||
 | 
			
		||||
	drawPolygon(ctx, 4, p[0][0], i[0], p[1][0], i[1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBoxStd(DrawingContext *ctx, const char *word, char base)
 | 
			
		||||
{
 | 
			
		||||
	char word1[100];
 | 
			
		||||
	char word2[100];
 | 
			
		||||
 | 
			
		||||
	int len = strlen(word);
 | 
			
		||||
	if(len*2 + 4 > 100)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < len; i++) {
 | 
			
		||||
		word1[i] = word1[2*len+2-i] = word[i];
 | 
			
		||||
		word2[i] = word2[2*len+2-i] = word[i];
 | 
			
		||||
	}
 | 
			
		||||
	word1[2*len+3] = 0;
 | 
			
		||||
	word2[2*len+3] = 0;
 | 
			
		||||
 | 
			
		||||
	LOOP(i) word1[len+i] = (base-'A'+6+i+1)%3+'a';
 | 
			
		||||
	LOOP(i) word2[len+i] = (base-'A'+6-i-1)%3+'a';
 | 
			
		||||
 | 
			
		||||
//	printf("Words: %s %s\n", word1, word2);
 | 
			
		||||
 | 
			
		||||
	drawBox(ctx, word1, word2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int compareAngle(const void *x, const void *y)
 | 
			
		||||
{
 | 
			
		||||
	return ((double*)x)[2] > ((double*)y)[2] ? 1 : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int computeLimitCurve()
 | 
			
		||||
{
 | 
			
		||||
	int p = 5, q = 5, r = 5;
 | 
			
		||||
	int k = 2, l = 2, m = 2;
 | 
			
		||||
 | 
			
		||||
	int column = use_repelling ? 2 : 0;
 | 
			
		||||
 | 
			
		||||
	generate_triangle_group(group, n_group_elements, p, q, r);
 | 
			
		||||
 | 
			
		||||
	// do first in the Fuchsian case to get the angles
 | 
			
		||||
	cartanMatrix(cartan, M_PI/p, M_PI/q, M_PI/r, 1.0);
 | 
			
		||||
	initializeTriangleGenerators(gen, cartan);
 | 
			
		||||
	gsl_matrix_set_identity(matrices[0]);
 | 
			
		||||
	for(int i = 1; i < n_group_elements; i++)
 | 
			
		||||
		multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]);
 | 
			
		||||
	diagonalize_symmetric_form(cartan, cob, ws);
 | 
			
		||||
	multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
 | 
			
		||||
	int ev_count_fuchsian = real_eigenvectors(coxeter, coxeter_fixedpoints, ws);
 | 
			
		||||
 | 
			
		||||
	if(ev_count_fuchsian != 3)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < n_group_elements; i++) {
 | 
			
		||||
		multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
 | 
			
		||||
		limit_curve[3*i+2] = atan2(
 | 
			
		||||
			gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column),
 | 
			
		||||
			gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column));
 | 
			
		||||
	for(int i = 0; i < ctx->n_group_elements; i++) {
 | 
			
		||||
		multiply_many(ws, fixedpoints_pos, 3, cob_pos, elements[i], coxeter_fixedpoints_pos);
 | 
			
		||||
		ctx->limit_curve[3*i+2] = atan2(
 | 
			
		||||
			gsl_matrix_get(fixedpoints_pos, 0, column)/gsl_matrix_get(fixedpoints_pos, 2, column),
 | 
			
		||||
			gsl_matrix_get(fixedpoints_pos, 1, column)/gsl_matrix_get(fixedpoints_pos, 2, column));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// now to it again to calculate x and y coordinates
 | 
			
		||||
	cartanMatrix(cartan, M_PI*k/p, M_PI*l/q, M_PI*m/r, parameter);
 | 
			
		||||
	initializeTriangleGenerators(gen, cartan);
 | 
			
		||||
	gsl_matrix_set_identity(matrices[0]);
 | 
			
		||||
	for(int i = 1; i < n_group_elements; i++)
 | 
			
		||||
		multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]);
 | 
			
		||||
	gsl_matrix_memcpy(cob, cartan); // is this a good choice of basis
 | 
			
		||||
//	gsl_matrix_set_identity(cob);
 | 
			
		||||
	// now do it again to calculate x and y coordinates
 | 
			
		||||
	initializeTriangleGenerators(gen, ctx->cartan);
 | 
			
		||||
	gsl_matrix_set_identity(elements[0]);
 | 
			
		||||
	for(int i = 1; i < ctx->n_group_elements; i++)
 | 
			
		||||
		multiply(elements[group[i].parent->id], gen[group[i].letter], elements[i]);
 | 
			
		||||
	multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
 | 
			
		||||
	int ev_count = real_eigenvectors(coxeter, coxeter_fixedpoints, ws);
 | 
			
		||||
 | 
			
		||||
	if(ev_count == 1)
 | 
			
		||||
		column = 0;
 | 
			
		||||
	if(ev_count == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
		goto error_out;
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < n_group_elements; i++) {
 | 
			
		||||
		multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
 | 
			
		||||
	for(int i = 0; i < ctx->n_group_elements; i++) {
 | 
			
		||||
		multiply_many(ws, fixedpoints, 3, ctx->cob, elements[i], coxeter_fixedpoints);
 | 
			
		||||
 | 
			
		||||
		limit_curve[3*i] = gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column);
 | 
			
		||||
		limit_curve[3*i+1] = gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column);
 | 
			
		||||
		ctx->limit_curve[3*i  ] = gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column);
 | 
			
		||||
		ctx->limit_curve[3*i+1] = gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qsort(limit_curve, n_group_elements, 3*sizeof(double), compareAngle);
 | 
			
		||||
	qsort(ctx->limit_curve, ctx->n_group_elements, 3*sizeof(double), compareAngle);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawBoxes(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 0);
 | 
			
		||||
	drawTriangle(ctx, "abc");
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 1);
 | 
			
		||||
	drawTriangle(ctx, "aca abc aca");
 | 
			
		||||
	drawTriangle(ctx, "acac abc caca");
 | 
			
		||||
	drawTriangle(ctx, "acaca abc acaca");
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0.8, 0);
 | 
			
		||||
	drawTriangle(ctx, "cac abc cac");
 | 
			
		||||
	drawTriangle(ctx, "caca abc acac");
 | 
			
		||||
	drawTriangle(ctx, "cacac abc cacac");
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 0);
 | 
			
		||||
	drawBoxStd(ctx, "c", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "a", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "b", 'B');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 0);
 | 
			
		||||
	drawBoxStd(ctx, "ca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cac", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "acac", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "ac", 'C');
 | 
			
		||||
 | 
			
		||||
	drawBoxStd(ctx, "aca cb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "aca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "aca bc", 'C');
 | 
			
		||||
 | 
			
		||||
	drawBoxStd(ctx, "caca cb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "caca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "caca bc", 'C');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 0, 1);
 | 
			
		||||
	drawBoxStd(ctx, "ca bc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca bcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "ca bcbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca cbcb", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "ca cbc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "ca cb", 'B');
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 1, 0);
 | 
			
		||||
//	drawBoxStd(ctx, "ca bc", 'C');
 | 
			
		||||
	drawBoxStd(ctx, "cabc ba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc bab", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "cabc baba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc abab", 'B');
 | 
			
		||||
	drawBoxStd(ctx, "cabc aba", 'A');
 | 
			
		||||
	drawBoxStd(ctx, "cabc ab", 'B');
 | 
			
		||||
	*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawReflectors(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	gsl_matrix *tmp = ws->stack[10];
 | 
			
		||||
	gsl_matrix *tmp2 = ws->stack[11];
 | 
			
		||||
	point_t p[3];
 | 
			
		||||
 | 
			
		||||
	// points
 | 
			
		||||
	cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
 | 
			
		||||
	LOOP(i) p[i].x = gsl_matrix_get(cob, 0, i) / gsl_matrix_get(cob, 2, i);
 | 
			
		||||
	LOOP(i) p[i].y = gsl_matrix_get(cob, 1, i) / gsl_matrix_get(cob, 2, i);
 | 
			
		||||
	LOOP(i) drawPoint(ctx, p[i]);
 | 
			
		||||
 | 
			
		||||
	// lines
 | 
			
		||||
	invert(cob, tmp2, ws);
 | 
			
		||||
	multiply(cartan, tmp2, tmp);
 | 
			
		||||
	LOOP(i) drawImplicitLine(ctx, gsl_matrix_get(tmp, i, 0), gsl_matrix_get(tmp, i, 1), gsl_matrix_get(tmp, i, 2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drawAttractors(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	point_t p[3][3];
 | 
			
		||||
 | 
			
		||||
	fixedPoints("abc", p[0]);
 | 
			
		||||
	fixedPoints("bca", p[1]);
 | 
			
		||||
	fixedPoints("cab", p[2]);
 | 
			
		||||
 | 
			
		||||
	double color[3][3] = {{1,0,0},{0,0.7,0},{0,0,1}};
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) {
 | 
			
		||||
		cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
 | 
			
		||||
		drawPoint(ctx, p[i][j]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOOP(i) LOOP(j) {
 | 
			
		||||
		cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
 | 
			
		||||
		drawLine(ctx, p[i][j], p[i][(j+1)%3]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void draw(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	cairo_t *C = ctx->cairo;
 | 
			
		||||
 | 
			
		||||
	cairo_set_source_rgb(C, 1, 1, 1);
 | 
			
		||||
	cairo_paint(C);
 | 
			
		||||
 | 
			
		||||
	cairo_set_matrix(C, &ctx->matrix);
 | 
			
		||||
 | 
			
		||||
	// defaults; use save/restore whenever these are changed
 | 
			
		||||
	cairo_set_line_width(C, 1.0/ctx->scalefactor);
 | 
			
		||||
	cairo_set_font_size(C, 16);
 | 
			
		||||
	cairo_set_line_join(C, CAIRO_LINE_JOIN_BEVEL);
 | 
			
		||||
	cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
 | 
			
		||||
	if(limit_curve_valid) {
 | 
			
		||||
		if(show_limit) {
 | 
			
		||||
			cairo_save(C);
 | 
			
		||||
 | 
			
		||||
			int previous_inside = 0;
 | 
			
		||||
			for(int i = 0; i < n_group_elements; i++) {
 | 
			
		||||
				double x = limit_curve[3*i];
 | 
			
		||||
				double y = limit_curve[3*i+1];
 | 
			
		||||
 | 
			
		||||
				cairo_user_to_device(C, &x, &y);
 | 
			
		||||
 | 
			
		||||
				if(-x < ctx->width && x < 3*ctx->width && -y < ctx->height && y < 3*ctx->height) {
 | 
			
		||||
					if(limit_with_lines) {
 | 
			
		||||
						if(!previous_inside)
 | 
			
		||||
							cairo_move_to(C, limit_curve[3*i], limit_curve[3*i+1]);
 | 
			
		||||
						else
 | 
			
		||||
							cairo_line_to(C, limit_curve[3*i], limit_curve[3*i+1]);
 | 
			
		||||
					} else {
 | 
			
		||||
						cairo_move_to(C, limit_curve[3*i], limit_curve[3*i+1]);
 | 
			
		||||
						cairo_close_path(C);
 | 
			
		||||
					}
 | 
			
		||||
					previous_inside = 1;
 | 
			
		||||
				} else {
 | 
			
		||||
					previous_inside = 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(!limit_with_lines) { // draw dots instead of lines
 | 
			
		||||
				cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
 | 
			
		||||
				cairo_set_line_width(C, 3.0/ctx->scalefactor);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			cairo_set_source_rgb(C, 0, 0, 0);
 | 
			
		||||
			cairo_stroke(C);
 | 
			
		||||
 | 
			
		||||
			cairo_restore(C);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(show_boxes)
 | 
			
		||||
			drawBoxes(ctx);
 | 
			
		||||
 | 
			
		||||
		if(show_attractors)
 | 
			
		||||
			drawAttractors(ctx);
 | 
			
		||||
 | 
			
		||||
		if(show_reflectors)
 | 
			
		||||
			drawReflectors(ctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cairo_identity_matrix(C);
 | 
			
		||||
 | 
			
		||||
	cairo_move_to(C, 15, 30);
 | 
			
		||||
	cairo_set_source_rgb(C, 0, 0, 0);
 | 
			
		||||
	char buf[100];
 | 
			
		||||
	sprintf(buf, "t = exp(%.8f) = %.8f", log(parameter), parameter);
 | 
			
		||||
	cairo_show_text(C, buf);
 | 
			
		||||
 | 
			
		||||
	cairo_surface_flush(cairo_get_target(C));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup()
 | 
			
		||||
{
 | 
			
		||||
	n_group_elements = 50000;
 | 
			
		||||
	limit_curve = malloc(3*n_group_elements*sizeof(double));
 | 
			
		||||
	group = malloc(n_group_elements*sizeof(groupelement_t));
 | 
			
		||||
	ws = workspace_alloc(3);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) gen[i] = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	matrices = malloc(n_group_elements*sizeof(gsl_matrix*));
 | 
			
		||||
	for(int i = 0; i < n_group_elements; i++)
 | 
			
		||||
		matrices[i] = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	cartan = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	cob = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	coxeter = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	coxeter_fixedpoints = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	fixedpoints = gsl_matrix_alloc(3, 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy()
 | 
			
		||||
{
 | 
			
		||||
	free(limit_curve);
 | 
			
		||||
	free(group);
 | 
			
		||||
	workspace_free(ws);
 | 
			
		||||
 | 
			
		||||
	LOOP(i) gsl_matrix_free(gen[i]);
 | 
			
		||||
	for(int i = 0; i < n_group_elements; i++)
 | 
			
		||||
		gsl_matrix_free(matrices[i]);
 | 
			
		||||
	free(matrices);
 | 
			
		||||
	gsl_matrix_free(cartan);
 | 
			
		||||
	gsl_matrix_free(cob);
 | 
			
		||||
	gsl_matrix_free(coxeter);
 | 
			
		||||
	gsl_matrix_free(coxeter_fixedpoints);
 | 
			
		||||
	gsl_matrix_free(fixedpoints);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print(DrawingContext *screen)
 | 
			
		||||
{
 | 
			
		||||
	DrawingContext file;
 | 
			
		||||
	cairo_surface_t *surface;
 | 
			
		||||
 | 
			
		||||
	char filename[100];
 | 
			
		||||
	time_t t = time(NULL);
 | 
			
		||||
	strftime(filename, sizeof(filename), "screenshot_%Y%m%d_%H%M%S.pdf", localtime(&t));
 | 
			
		||||
 | 
			
		||||
	file.width = screen->width;
 | 
			
		||||
	file.height = screen->width / sqrt(2.0);
 | 
			
		||||
	file.matrix = screen->matrix;
 | 
			
		||||
	file.matrix.y0 += ((double)file.height - (double)screen->height) / 2.0; // recenter vertically
 | 
			
		||||
	updateDimensions(&file);
 | 
			
		||||
 | 
			
		||||
	surface = cairo_pdf_surface_create(filename, (double)file.width, (double)file.height);
 | 
			
		||||
    file.cairo = cairo_create(surface);
 | 
			
		||||
 | 
			
		||||
	draw(&file);
 | 
			
		||||
 | 
			
		||||
	cairo_destroy(file.cairo);
 | 
			
		||||
	cairo_surface_destroy(surface);
 | 
			
		||||
 | 
			
		||||
	printf("Wrote sceenshot to file: %s\n", filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int processEvent(GraphicsInfo *info, XEvent *ev)
 | 
			
		||||
{
 | 
			
		||||
	int state;
 | 
			
		||||
	unsigned long key;
 | 
			
		||||
 | 
			
		||||
	switch(ev->type) {
 | 
			
		||||
 | 
			
		||||
	case KeyPress:
 | 
			
		||||
		state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
 | 
			
		||||
		key = XkbKeycodeToKeysym(ev->xkey.display, ev->xkey.keycode, 0, !!(state & ShiftMask));
 | 
			
		||||
		printf("Key pressed: %ld\n", key);
 | 
			
		||||
 | 
			
		||||
		switch(key) {
 | 
			
		||||
		case XK_Down:
 | 
			
		||||
			parameter /= exp(0.002);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Up:
 | 
			
		||||
			parameter *= exp(0.002);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Left:
 | 
			
		||||
			parameter /= exp(0.0001);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Right:
 | 
			
		||||
			parameter *= exp(0.0001);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Page_Down:
 | 
			
		||||
			parameter /= exp(0.2);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Page_Up:
 | 
			
		||||
			parameter *= exp(0.2);
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case ' ':
 | 
			
		||||
			parameter = 2.890053638;
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Return:
 | 
			
		||||
			parameter = 2.76375163;
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
			break;
 | 
			
		||||
		case 'm':
 | 
			
		||||
			printf("info->context->matrix.xx = %f;\n", info->context->matrix.xx);
 | 
			
		||||
			printf("info->context->matrix.xy = %f;\n", info->context->matrix.xy);
 | 
			
		||||
			printf("info->context->matrix.x0 = %f;\n", info->context->matrix.x0);
 | 
			
		||||
			printf("info->context->matrix.yx = %f;\n", info->context->matrix.yx);
 | 
			
		||||
			printf("info->context->matrix.yy = %f;\n", info->context->matrix.yy);
 | 
			
		||||
			printf("info->context->matrix.y0 = %f;\n", info->context->matrix.y0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'b':
 | 
			
		||||
			show_boxes = !show_boxes;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'a':
 | 
			
		||||
			show_attractors = !show_attractors;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			show_reflectors = !show_reflectors;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'L':
 | 
			
		||||
			limit_with_lines = !limit_with_lines;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'l':
 | 
			
		||||
			show_limit = !show_limit;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'p':
 | 
			
		||||
			print(info->context);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			use_repelling = !use_repelling;
 | 
			
		||||
			limit_curve_valid = computeLimitCurve();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return STATUS_REDRAW;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return STATUS_NOTHING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
	GraphicsInfo *info;
 | 
			
		||||
 | 
			
		||||
	parameter = 3.0;
 | 
			
		||||
 | 
			
		||||
	setup();
 | 
			
		||||
	limit_curve_valid = computeLimitCurve();
 | 
			
		||||
 | 
			
		||||
	info = initCairo(0, KeyPressMask, 200, 200, "Triangle group");
 | 
			
		||||
	if(!info)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	DrawingContext *ctx = info->context;
 | 
			
		||||
 | 
			
		||||
	ctx->matrix.xx = 837.930824;
 | 
			
		||||
	ctx->matrix.xy = -712.651341;
 | 
			
		||||
	ctx->matrix.x0 = 180.427716;
 | 
			
		||||
	ctx->matrix.yx = 712.651341;
 | 
			
		||||
	ctx->matrix.yy = 837.930824;
 | 
			
		||||
	ctx->matrix.y0 = 1412.553240;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	info->context->matrix.xx = 1636.583641;
 | 
			
		||||
	info->context->matrix.xy = -1391.897150;
 | 
			
		||||
	info->context->matrix.x0 = 975.772883;
 | 
			
		||||
	info->context->matrix.yx = 1391.897150;
 | 
			
		||||
	info->context->matrix.yy = 1636.583641;
 | 
			
		||||
	info->context->matrix.y0 = 2446.174297;
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	updateDimensions(ctx);
 | 
			
		||||
 | 
			
		||||
	startTimer(info);
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
		int result = checkEvents(info, processEvent, NULL);
 | 
			
		||||
		if(result == STATUS_QUIT)
 | 
			
		||||
			return 0;
 | 
			
		||||
		else if(result == STATUS_REDRAW) {
 | 
			
		||||
			struct timeval current_time;
 | 
			
		||||
			double start_time, intermediate_time, end_time;
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			start_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
 | 
			
		||||
			updateDimensions(info->context);
 | 
			
		||||
			draw(info->context);
 | 
			
		||||
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			intermediate_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
 | 
			
		||||
			cairo_set_source_surface(info->front_context, info->buffer_surface, 0, 0);
 | 
			
		||||
			cairo_paint(info->front_context);
 | 
			
		||||
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			end_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
			printf("drawing finished in %.2f milliseconds, of which %.2f milliseconds were buffer switching\n", (end_time - start_time) * 1000, (end_time - intermediate_time) * 1000);
 | 
			
		||||
		}
 | 
			
		||||
		waitUpdateTimer(info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroyCairo(info);
 | 
			
		||||
 | 
			
		||||
	destroy();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	ctx->limit_curve_valid = 1;
 | 
			
		||||
 | 
			
		||||
	success = 1;
 | 
			
		||||
 | 
			
		||||
error_out:
 | 
			
		||||
	releaseTempMatrices(ctx, 11+ctx->n_group_elements);
 | 
			
		||||
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										289
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,289 @@
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <cairo/cairo-pdf.h>
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
 | 
			
		||||
#include "main.h"
 | 
			
		||||
#include "initcairo.h"
 | 
			
		||||
#include "triangle.h"
 | 
			
		||||
#include "linalg.h"
 | 
			
		||||
 | 
			
		||||
#define TOGGLE(a) do { (a) = !(a); } while(0)
 | 
			
		||||
 | 
			
		||||
DrawingContext *screen_context;
 | 
			
		||||
 | 
			
		||||
// setup everything except cairo and dim, which will be provided by the graphics system
 | 
			
		||||
void setupContext(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	ctx->n_group_elements = NUM_GROUP_ELEMENTS;
 | 
			
		||||
	ctx->p[0] = 5;
 | 
			
		||||
	ctx->p[1] = 5;
 | 
			
		||||
	ctx->p[2] = 5;
 | 
			
		||||
	ctx->k[0] = 2;
 | 
			
		||||
	ctx->k[1] = 2;
 | 
			
		||||
	ctx->k[2] = 2;
 | 
			
		||||
	ctx->parameter = 3.0;
 | 
			
		||||
	ctx->show_boxes = 0;
 | 
			
		||||
	ctx->show_attractors = 0;
 | 
			
		||||
	ctx->show_reflectors = 0;
 | 
			
		||||
	ctx->show_limit= 1;
 | 
			
		||||
	ctx->limit_with_lines = 1;
 | 
			
		||||
	ctx->use_repelling = 0;
 | 
			
		||||
 | 
			
		||||
	ctx->limit_curve = malloc(3*ctx->n_group_elements*sizeof(double));
 | 
			
		||||
	ctx->limit_curve_valid = 0;
 | 
			
		||||
 | 
			
		||||
	ctx->group = malloc(ctx->n_group_elements*sizeof(groupelement_t));
 | 
			
		||||
	generate_triangle_group(ctx->group, ctx->n_group_elements, ctx->p[0], ctx->p[1], ctx->p[2]);
 | 
			
		||||
 | 
			
		||||
	// the temporary stuff
 | 
			
		||||
	ctx->cartan = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	ctx->cob = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	ctx->ws = workspace_alloc(3);
 | 
			
		||||
	ctx->tmp = malloc(MAX_TEMP_MATRICES*sizeof(gsl_matrix*));
 | 
			
		||||
	for(int i = 0; i < MAX_TEMP_MATRICES; i++)
 | 
			
		||||
		ctx->tmp[i] = gsl_matrix_alloc(3, 3);
 | 
			
		||||
	ctx->tmp_used = 0;
 | 
			
		||||
	ctx->tmp_vec = malloc(MAX_TEMP_MATRICES*sizeof(gsl_vector*));
 | 
			
		||||
	for(int i = 0; i < MAX_TEMP_MATRICES; i++)
 | 
			
		||||
		ctx->tmp_vec[i] = gsl_vector_alloc(3);
 | 
			
		||||
	ctx->tmp_vec_used = 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroyContext(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	free(ctx->limit_curve);
 | 
			
		||||
	free(ctx->group);
 | 
			
		||||
 | 
			
		||||
	gsl_matrix_free(ctx->cartan);
 | 
			
		||||
	gsl_matrix_free(ctx->cob);
 | 
			
		||||
 | 
			
		||||
	workspace_free(ctx->ws);
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < MAX_TEMP_MATRICES; i++)
 | 
			
		||||
		gsl_matrix_free(ctx->tmp[i]);
 | 
			
		||||
	free(ctx->tmp);
 | 
			
		||||
	for(int i = 0; i < MAX_TEMP_VECTORS; i++)
 | 
			
		||||
		gsl_vector_free(ctx->tmp_vec[i]);
 | 
			
		||||
	free(ctx->tmp_vec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void updateMatrices(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	double angle[3];
 | 
			
		||||
	LOOP(i) angle[i] = M_PI*ctx->k[i]/ctx->p[i];
 | 
			
		||||
	cartanMatrix(ctx->cartan, angle[0], angle[1], angle[2], ctx->parameter);
 | 
			
		||||
	gsl_matrix_memcpy(ctx->cob, ctx->cartan); // is this a good choice of basis
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print(DrawingContext *screen)
 | 
			
		||||
{
 | 
			
		||||
	DrawingContext file;
 | 
			
		||||
	DimensionsInfo dim;
 | 
			
		||||
	cairo_surface_t *surface;
 | 
			
		||||
 | 
			
		||||
	char filename[100];
 | 
			
		||||
	time_t t = time(NULL);
 | 
			
		||||
	strftime(filename, sizeof(filename), "screenshot_%Y%m%d_%H%M%S.pdf", localtime(&t));
 | 
			
		||||
 | 
			
		||||
	dim.width = screen->dim->width;
 | 
			
		||||
	dim.height = screen->dim->width / sqrt(2.0);
 | 
			
		||||
	dim.matrix = screen->dim->matrix;
 | 
			
		||||
	dim.matrix.y0 += ((double)dim.height - (double)screen->dim->height) / 2.0; // recenter vertically
 | 
			
		||||
	updateDimensions(&dim);
 | 
			
		||||
	file.dim = &dim;
 | 
			
		||||
 | 
			
		||||
	surface = cairo_pdf_surface_create(filename, (double)dim.width, (double)dim.height);
 | 
			
		||||
    file.cairo = cairo_create(surface);
 | 
			
		||||
 | 
			
		||||
	draw(&file);
 | 
			
		||||
 | 
			
		||||
	cairo_destroy(file.cairo);
 | 
			
		||||
	cairo_surface_destroy(surface);
 | 
			
		||||
 | 
			
		||||
	printf("Wrote sceenshot to file: %s\n", filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int processEvent(GraphicsInfo *info, XEvent *ev)
 | 
			
		||||
{
 | 
			
		||||
	int state;
 | 
			
		||||
	unsigned long key;
 | 
			
		||||
 | 
			
		||||
	switch(ev->type) {
 | 
			
		||||
 | 
			
		||||
	case KeyPress:
 | 
			
		||||
		state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
 | 
			
		||||
		key = XkbKeycodeToKeysym(ev->xkey.display, ev->xkey.keycode, 0, !!(state & ShiftMask));
 | 
			
		||||
		printf("Key pressed: %ld\n", key);
 | 
			
		||||
 | 
			
		||||
		switch(key) {
 | 
			
		||||
		case XK_Down:
 | 
			
		||||
			screen_context->parameter /= exp(0.002);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Up:
 | 
			
		||||
			screen_context->parameter *= exp(0.002);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Left:
 | 
			
		||||
			screen_context->parameter /= exp(0.0001);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Right:
 | 
			
		||||
			screen_context->parameter *= exp(0.0001);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Page_Down:
 | 
			
		||||
			screen_context->parameter /= exp(0.2);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Page_Up:
 | 
			
		||||
			screen_context->parameter *= exp(0.2);
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case ' ':
 | 
			
		||||
			screen_context->parameter = 2.890053638;
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case XK_Return:
 | 
			
		||||
			screen_context->parameter = 2.76375163;
 | 
			
		||||
			updateMatrices(screen_context);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'm':
 | 
			
		||||
			printf("matrix.xx = %f;\n", info->dim->matrix.xx);
 | 
			
		||||
			printf("matrix.xy = %f;\n", info->dim->matrix.xy);
 | 
			
		||||
			printf("matrix.x0 = %f;\n", info->dim->matrix.x0);
 | 
			
		||||
			printf("matrix.yx = %f;\n", info->dim->matrix.yx);
 | 
			
		||||
			printf("matrix.yy = %f;\n", info->dim->matrix.yy);
 | 
			
		||||
			printf("matrix.y0 = %f;\n", info->dim->matrix.y0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'b':
 | 
			
		||||
			TOGGLE(screen_context->show_boxes);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'a':
 | 
			
		||||
			TOGGLE(screen_context->show_attractors);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			TOGGLE(screen_context->show_reflectors);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'L':
 | 
			
		||||
			TOGGLE(screen_context->limit_with_lines);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'l':
 | 
			
		||||
			TOGGLE(screen_context->show_limit);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'p':
 | 
			
		||||
			print(screen_context);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			TOGGLE(screen_context->use_repelling);
 | 
			
		||||
			computeLimitCurve(screen_context);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return STATUS_REDRAW;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return STATUS_NOTHING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
	GraphicsInfo *info;
 | 
			
		||||
 | 
			
		||||
	screen_context = malloc(sizeof(DrawingContext));
 | 
			
		||||
	setupContext(screen_context);
 | 
			
		||||
	updateMatrices(screen_context);
 | 
			
		||||
	computeLimitCurve(screen_context);
 | 
			
		||||
 | 
			
		||||
	// do stuff
 | 
			
		||||
/*
 | 
			
		||||
	DrawingContext *ctx = screen_context;
 | 
			
		||||
	gsl_matrix *tmp = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *ev = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix *evinv = getTempMatrix(ctx);
 | 
			
		||||
	gsl_matrix **gen = getTempMatrices(ctx, 3);
 | 
			
		||||
	gsl_matrix *transform = getTempMatrix(ctx);
 | 
			
		||||
	vector_t eigenvectors[3][3];
 | 
			
		||||
	char words[3][4] = {"abc", "bca", "cab"};
 | 
			
		||||
 | 
			
		||||
	initializeTriangleGenerators(gen, ctx->cartan);
 | 
			
		||||
 | 
			
		||||
	gsl_matrix_set_identity(tmp);
 | 
			
		||||
	for(int j = 0; j < strlen(words[0]); j++)
 | 
			
		||||
		multiply_right(tmp, gen[words[0][j]-'a'], ctx->ws);
 | 
			
		||||
	real_eigenvectors(tmp, ev, ctx->ws);
 | 
			
		||||
	invert(ev, evinv, ctx->ws);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	LOOP(i) {
 | 
			
		||||
		gsl_matrix_set_identity(tmp);
 | 
			
		||||
		for(int j = 0; j < strlen(words[i]); j++)
 | 
			
		||||
			multiply_right(tmp, gen[words[i][j]-'a'], ctx->ws);
 | 
			
		||||
		real_eigenvectors(tmp, ev, ctx->ws);
 | 
			
		||||
		LOOP(j) LOOP(k) eigenvectors[i][j].x[k] = gsl_matrix_get(ev, k, j);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// solve the following: (x + y + z) (l) = lambda w
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
	info = initCairo(0, KeyPressMask, 200, 200, "Triangle group");
 | 
			
		||||
	if(!info)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	info->dim->matrix.xx = 837.930824;
 | 
			
		||||
	info->dim->matrix.xy = -712.651341;
 | 
			
		||||
	info->dim->matrix.x0 = 180.427716;
 | 
			
		||||
	info->dim->matrix.yx = 712.651341;
 | 
			
		||||
	info->dim->matrix.yy = 837.930824;
 | 
			
		||||
	info->dim->matrix.y0 = 1412.553240;
 | 
			
		||||
	updateDimensions(info->dim);
 | 
			
		||||
 | 
			
		||||
	screen_context->dim = info->dim;
 | 
			
		||||
	screen_context->cairo = info->buffer_context;
 | 
			
		||||
 | 
			
		||||
	startTimer(info);
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
		int result = checkEvents(info, processEvent, NULL);
 | 
			
		||||
		if(result == STATUS_QUIT)
 | 
			
		||||
			return 0;
 | 
			
		||||
		else if(result == STATUS_REDRAW) {
 | 
			
		||||
			struct timeval current_time;
 | 
			
		||||
			double start_time, intermediate_time, end_time;
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			start_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
 | 
			
		||||
			draw(screen_context);
 | 
			
		||||
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			intermediate_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
 | 
			
		||||
			cairo_set_source_surface(info->front_context, info->buffer_surface, 0, 0);
 | 
			
		||||
			cairo_paint(info->front_context);
 | 
			
		||||
 | 
			
		||||
			gettimeofday(¤t_time, 0);
 | 
			
		||||
			end_time = current_time.tv_sec + current_time.tv_usec*1e-6;
 | 
			
		||||
			printf("drawing finished in %.2f milliseconds, of which %.2f milliseconds were buffer switching\n", (end_time - start_time) * 1000, (end_time - intermediate_time) * 1000);
 | 
			
		||||
		}
 | 
			
		||||
		waitUpdateTimer(info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(screen_context);
 | 
			
		||||
	destroyCairo(info);
 | 
			
		||||
	destroyContext(screen_context);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								main.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								main.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
#ifndef TRIANGLE_GROUP_MAIN_H
 | 
			
		||||
#define TRIANGLE_GROUP_MAIN_H
 | 
			
		||||
 | 
			
		||||
#include "triangle.h"
 | 
			
		||||
#include "linalg.h"
 | 
			
		||||
#include "initcairo.h"
 | 
			
		||||
 | 
			
		||||
#undef ERROR
 | 
			
		||||
#define ERROR(condition, msg, ...) if(condition){fprintf(stderr, msg, ##__VA_ARGS__); exit(1);}
 | 
			
		||||
#define LOOP(i) for(int i = 0; i < 3; i++)
 | 
			
		||||
 | 
			
		||||
#define NUM_GROUP_ELEMENTS 50000
 | 
			
		||||
#define MAX_TEMP_MATRICES 60000
 | 
			
		||||
#define MAX_TEMP_VECTORS 100
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	double x[3];
 | 
			
		||||
} vector_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	double x;
 | 
			
		||||
	double y;
 | 
			
		||||
} point_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	// infos about the screen to draw on
 | 
			
		||||
	cairo_t *cairo;
 | 
			
		||||
	DimensionsInfo *dim;
 | 
			
		||||
 | 
			
		||||
	// a priori parameter
 | 
			
		||||
	int p[3],k[3];
 | 
			
		||||
	double parameter;
 | 
			
		||||
	int n_group_elements;
 | 
			
		||||
	int show_boxes;
 | 
			
		||||
	int show_attractors;
 | 
			
		||||
	int show_reflectors;
 | 
			
		||||
	int show_limit;
 | 
			
		||||
	int limit_with_lines;
 | 
			
		||||
	int use_repelling;
 | 
			
		||||
	gsl_matrix *cartan, *cob;
 | 
			
		||||
 | 
			
		||||
    // precomputed and constant
 | 
			
		||||
	groupelement_t *group;
 | 
			
		||||
 | 
			
		||||
	// computed stuff
 | 
			
		||||
	double *limit_curve; // x, y, angle triples
 | 
			
		||||
	int limit_curve_valid;
 | 
			
		||||
 | 
			
		||||
	// temporary; matrices can only be freed from the top, but that's enough for us
 | 
			
		||||
	workspace_t *ws;
 | 
			
		||||
	gsl_matrix **tmp;
 | 
			
		||||
	int tmp_used;
 | 
			
		||||
	gsl_vector **tmp_vec;
 | 
			
		||||
	int tmp_vec_used;
 | 
			
		||||
} DrawingContext;
 | 
			
		||||
 | 
			
		||||
static gsl_matrix **getTempMatrices(DrawingContext *ctx, int n)
 | 
			
		||||
{
 | 
			
		||||
	ERROR(ctx->tmp_used + n > MAX_TEMP_MATRICES, "Ran out of temporary matrices. Consider increasing MAX_TEMP_MATRICES\n");
 | 
			
		||||
	int index = ctx->tmp_used;
 | 
			
		||||
	ctx->tmp_used += n;
 | 
			
		||||
	return ctx->tmp + index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gsl_matrix *getTempMatrix(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	return *getTempMatrices(ctx, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void releaseTempMatrices(DrawingContext *ctx, int n)
 | 
			
		||||
{
 | 
			
		||||
	ERROR(ctx->tmp_used - n < 0, "Released more matrices then in use\n");
 | 
			
		||||
	ctx->tmp_used -= n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gsl_vector **getTempVectors(DrawingContext *ctx, int n)
 | 
			
		||||
{
 | 
			
		||||
	ERROR(ctx->tmp_vec_used + n > MAX_TEMP_VECTORS, "Ran out of temporary vectors. Consider increasing MAX_TEMP_VECTORS\n");
 | 
			
		||||
	int index = ctx->tmp_vec_used;
 | 
			
		||||
	ctx->tmp_vec_used += n;
 | 
			
		||||
	return ctx->tmp_vec + index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gsl_vector *getTempVector(DrawingContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
	return *getTempVectors(ctx, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void releaseTempVectors(DrawingContext *ctx, int n)
 | 
			
		||||
{
 | 
			
		||||
	ERROR(ctx->tmp_vec_used - n < 0, "Released more vectors then in use\n");
 | 
			
		||||
	ctx->tmp_vec_used -= n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// implemented in limit_set.c
 | 
			
		||||
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s);
 | 
			
		||||
void initializeTriangleGenerators(gsl_matrix **gen, gsl_matrix *cartan);
 | 
			
		||||
int computeLimitCurve(DrawingContext *ctx);
 | 
			
		||||
 | 
			
		||||
// implemented in draw.c
 | 
			
		||||
vector_t cross(vector_t a, vector_t b);
 | 
			
		||||
int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out);
 | 
			
		||||
void drawPoint(DrawingContext *ctx, point_t p);
 | 
			
		||||
void drawSegment2d(DrawingContext *ctx, point_t a, point_t b);
 | 
			
		||||
void drawVector(DrawingContext *ctx, vector_t v);
 | 
			
		||||
void drawCovector(DrawingContext *ctx, vector_t v);
 | 
			
		||||
void drawSegment(DrawingContext *ctx, vector_t a, vector_t b);
 | 
			
		||||
void drawPolygon(DrawingContext *ctx, int sides, ...);
 | 
			
		||||
void drawTriangle(DrawingContext *ctx, const char *word);
 | 
			
		||||
void drawBox(DrawingContext *ctx, const char *word1, const char *word2);
 | 
			
		||||
void drawBoxStd(DrawingContext *ctx, const char *word, char base);
 | 
			
		||||
void drawReflectors(DrawingContext *ctx);
 | 
			
		||||
void drawAttractors(DrawingContext *ctx);
 | 
			
		||||
void drawBoxes(DrawingContext *ctx);
 | 
			
		||||
void drawLimitCurve(DrawingContext *ctx);
 | 
			
		||||
void drawText(DrawingContext *ctx);
 | 
			
		||||
void draw(DrawingContext *ctx);
 | 
			
		||||
 | 
			
		||||
// implemented in main.c
 | 
			
		||||
void setupContext(DrawingContext *ctx);
 | 
			
		||||
void destroyContext(DrawingContext *ctx);
 | 
			
		||||
void print(DrawingContext *screen);
 | 
			
		||||
int processEvent(GraphicsInfo *info, XEvent *ev);
 | 
			
		||||
void updateMatrices(DrawingContext *ctx);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user