Compare commits

..

3 Commits

Author SHA1 Message Date
Florian Stecker
78769593a7 movie command line arguments 2023-02-05 15:10:16 -05:00
Florian Stecker
a8b4bb7c2c implement rotation group and play around with it a bit 2022-07-29 14:38:48 +09:00
Florian Stecker
35932782e9 new .gitignore 2022-03-02 10:53:19 -06:00
8 changed files with 1040 additions and 526 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
limit_set
*.pdf

View File

@ -1,50 +0,0 @@
# triangle_group_limit_set - visualizer for triangle group limit sets in the projective plane
This program visualizes the fractal limit set of triangle groups in SL(3,R) in the projective plane. For the mathematical details, see [our paper].
## Installation & Prerequisites ##
This program is written C and only runs on Linux with the X window system (because that's what I happen to be using). It uses [Cairo] for drawing and X11 for input. We also require the [Gnu Scientific Library (GSL)] including CBLAS.
To build, just make sure GCC as well as these libraries are installed, and run
make
Then we can run it for example like this:
./limit_set 5 5 5 1 1 1 1.0
The arguments are 6 integers (p1, p2, p3, q1, q2, q3) and a floating point numbers t. Together they discribe the triangle group under consideration (t can be changed with the arrow keys).
## Key bindings
Drag the mouse to move the image, drag with Shift pressed to rotate.
| Key | function |
|----------|-----------------------------------------------------------------------------------------------------|
| PageUp | increase t by 2% |
| PageDown | decrease t by 2% |
| Right | increase t by 0.2% |
| Left | decreaes t by 0.2% |
| Up | increase t by 0.002% |
| Down | decrease t by 0.002% |
| Space | (reset t to original value) |
| R | cycle through affine charts |
| l | show limit curve |
| L | show limit curve as line or as points |
| f | generate limit curve using attracting / repelling fixed points of conjugates of the Coxeter element |
| d | show dual limit curve |
| r | show fixed points and lines of generating reflections |
| a | show fixed points and lines of Coxeter elements |
| c | show the orbit of an arbitrary point (point can be changed with Shift+Click) |
| b | show certain conics touching the limit curve |
| B | show the "boxes" used to approximate the limit curve |
| p | save a screenshot of the current image (in PDF format) |
| t | toggle info text |
| i | (print some info to terminal?) |
| x | (show rotated reflectors?) |
| M | (make a movie) |
[Cairo]: https://cairographics.org/
[Gnu Scientific Library (GSL)]: https://www.gnu.org/software/gsl/
[our paper]: https://arxiv.org/abs/2106.11349

644
draw.c
View File

@ -46,21 +46,22 @@ int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out)
{ {
gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix *tmp = getTempMatrix(ctx->ws);
gsl_matrix *ev = getTempMatrix(ctx->ws); gsl_matrix *ev = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(tmp); gsl_matrix_set_identity(tmp);
for(int i = 0; i < strlen(word); i++) { for(int i = 0; i < strlen(word); i++) {
if(word[i] == ' ') if(word[i] >= 'a' && word[i] <= 'c')
continue; multiply_right(tmp, gen[word[i]-'a'], ctx->ws);
multiply_right(tmp, gen[word[i]-'a'], ctx->ws); else if(word[i] >= 'A' && word[i] <= 'C')
multiply_right(tmp, gen[word[i]-'A'+3], ctx->ws);
} }
int count = real_eigenvectors(tmp, ev, ctx->ws); int count = real_eigenvectors(tmp, ev, ctx->ws);
LOOP(i) LOOP(j) out[i].x[j] = gsl_matrix_get(ev, j, i); LOOP(i) LOOP(j) out[i].x[j] = gsl_matrix_get(ev, j, i);
releaseTempMatrices(ctx->ws, 5); releaseTempMatrices(ctx->ws, 8);
return count; return count;
} }
@ -69,9 +70,9 @@ int wordEigenvalues(DrawingContext *ctx, const char *word, double *out)
{ {
gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix *tmp = getTempMatrix(ctx->ws);
gsl_vector *ev = getTempVector(ctx->ws); gsl_vector *ev = getTempVector(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(tmp); gsl_matrix_set_identity(tmp);
for(int i = 0; i < strlen(word); i++) { for(int i = 0; i < strlen(word); i++) {
@ -83,7 +84,7 @@ int wordEigenvalues(DrawingContext *ctx, const char *word, double *out)
LOOP(i) out[i] = gsl_vector_get(ev, i); LOOP(i) out[i] = gsl_vector_get(ev, i);
releaseTempMatrices(ctx->ws, 4); releaseTempMatrices(ctx->ws, 7);
releaseTempVectors(ctx->ws, 1); releaseTempVectors(ctx->ws, 1);
return count; return count;
@ -96,10 +97,20 @@ void drawPoint(DrawingContext *ctx, point_t p)
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
cairo_save(C); cairo_save(C);
cairo_arc(C, p.x, p.y, 4.0/ctx->dim->scalefactor, 0, 2*M_PI); cairo_arc(C, p.x, p.y, 3.0/ctx->dim->scalefactor, 0, 2*M_PI);
cairo_close_path(C); cairo_close_path(C);
cairo_fill(C); cairo_fill(C);
cairo_restore(C); cairo_restore(C);
/*
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) void drawSegment2d(DrawingContext *ctx, point_t a, point_t b)
@ -183,13 +194,22 @@ void drawSegmentWith(DrawingContext *ctx, vector_t a, vector_t b, vector_t line,
LOOP(i) x[i] = 0.0; LOOP(i) x[i] = 0.0;
LOOP(i) LOOP(j) { 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) 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); - 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 * line.x[j]; x[i] += cofactor * line.x[j];
} }
// t = parameter on segment of intersection with line, s(t) = a + (b-a)*t // t = parameter on segment of intersection with line, s(t) = a + (b-a)*t
tline = -(a_.x*x[0] + a_.y*x[1] + x[2])/((b_.x - a_.x)*x[0] + (b_.y - a_.y)*x[1]); tline = -(a_.x*x[0] + a_.y*x[1] + x[2])/((b_.x - a_.x)*x[0] + (b_.y - a_.y)*x[1]);
/*
printf("tline: %f\n", tline);
point_t s;
s.x = a_.x - (b_.x-a_.x)*tline;
s.y = a_.y - (b_.y-a_.y)*tline;
drawPoint(ctx, s);
*/
if((tline < 0 || tline > 1) != contains) { if((tline < 0 || tline > 1) != contains) {
drawSegment2d(ctx, a_, b_); drawSegment2d(ctx, a_, b_);
} else { // need to draw complementary segment } else { // need to draw complementary segment
@ -197,7 +217,6 @@ void drawSegmentWith(DrawingContext *ctx, vector_t a, vector_t b, vector_t line,
m.x = ctx->dim->center_x; m.x = ctx->dim->center_x;
m.y = ctx->dim->center_y; m.y = ctx->dim->center_y;
r = ctx->dim->radius; r = ctx->dim->radius;
// equation is coeff2 t^2 + 2 coeff1 t + coeff0 = 0 // equation is coeff2 t^2 + 2 coeff1 t + coeff0 = 0
coeff0 = (a_.x - m.x)*(a_.x - m.x) + (a_.y - m.y)*(a_.y - m.y) - r*r; coeff0 = (a_.x - m.x)*(a_.x - m.x) + (a_.y - m.y)*(a_.y - m.y) - r*r;
coeff1 = (a_.x - m.x)*(b_.x - a_.x) + (a_.y - m.y)*(b_.y - a_.y); coeff1 = (a_.x - m.x)*(b_.x - a_.x) + (a_.y - m.y)*(b_.y - a_.y);
@ -218,6 +237,7 @@ void drawSegmentWith(DrawingContext *ctx, vector_t a, vector_t b, vector_t line,
} }
// level 3: boxes and polygons // level 3: boxes and polygons
void drawPolygon(DrawingContext *ctx, int segments, int sides, ...) void drawPolygon(DrawingContext *ctx, int segments, int sides, ...)
{ {
va_list args; va_list args;
@ -308,13 +328,13 @@ void drawRotationOrbitFrame(DrawingContext *ctx, gsl_matrix *frame, vector_t sta
vector_t v[3], w; vector_t v[3], w;
point_t p; point_t p;
double parameter, startangle; double parameter, startangle;
int iterations = 200; int iterations = 2000;
gsl_matrix *inverse = getTempMatrix(ctx->ws); gsl_matrix *inverse = getTempMatrix(ctx->ws);
gsl_vector *start_v = getTempVector(ctx->ws); gsl_vector *start_v = getTempVector(ctx->ws);
gsl_vector *start_in_frame = getTempVector(ctx->ws); gsl_vector *start_in_frame = getTempVector(ctx->ws);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
// computeRotationMatrix(ctx, frame, word); // computeRotationMatrixFrame(ctx, frame, word);
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
LOOP(i) gsl_vector_set(start_v, i, start.x[i]); LOOP(i) gsl_vector_set(start_v, i, start.x[i]);
@ -350,7 +370,7 @@ void drawRotationOrbit(DrawingContext *ctx, const char *word, vector_t start)
{ {
gsl_matrix *frame = getTempMatrix(ctx->ws); gsl_matrix *frame = getTempMatrix(ctx->ws);
computeRotationMatrix(ctx, frame, word); computeRotationMatrixFrame(ctx, frame, word);
drawRotationOrbitFrame(ctx, frame, start); drawRotationOrbitFrame(ctx, frame, start);
releaseTempMatrices(ctx->ws, 1); releaseTempMatrices(ctx->ws, 1);
@ -368,7 +388,7 @@ void drawDualRotationOrbit(DrawingContext *ctx, const char *word, vector_t start
gsl_vector *start_in_frame = getTempVector(ctx->ws); gsl_vector *start_in_frame = getTempVector(ctx->ws);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
computeRotationMatrix(ctx, frame, word); computeRotationMatrixFrame(ctx, frame, word);
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
LOOP(i) gsl_vector_set(start_v, i, start.x[i]); LOOP(i) gsl_vector_set(start_v, i, start.x[i]);
@ -413,7 +433,7 @@ void drawArcWithOutput(DrawingContext *ctx, const char *word, vector_t start, ve
gsl_vector *vector_in_frame = getTempVector(ctx->ws); gsl_vector *vector_in_frame = getTempVector(ctx->ws);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
computeRotationMatrix(ctx, frame, word); computeRotationMatrixFrame(ctx, frame, word);
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
LOOP(i) gsl_vector_set(vector, i, start.x[i]); LOOP(i) gsl_vector_set(vector, i, start.x[i]);
@ -555,11 +575,10 @@ void drawAttractors(DrawingContext *ctx)
vector_t p[6][3]; vector_t p[6][3];
vector_t l[6][3]; vector_t l[6][3];
fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "cba", p[0]);
fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "bac", p[1]);
fixedPoints(ctx, "cab", p[2]); fixedPoints(ctx, "acb", p[2]);
// fixedPoints(ctx, "abacacbabc", p[3]); fixedPoints(ctx, "a cab a", p[3]);
// fixedPoints(ctx, "abcabcabcabcab", p[3]);
fixedPoints(ctx, "b abc b", p[4]); fixedPoints(ctx, "b abc b", p[4]);
fixedPoints(ctx, "c bca c", p[5]); fixedPoints(ctx, "c bca c", p[5]);
@ -633,6 +652,12 @@ void drawCurvedBox(DrawingContext *ctx, int base, const char *conj, int style)
fixedPoints(ctx, word, p[10]); fixedPoints(ctx, word, p[10]);
// conjugate_word("bca b abc b acb", modifier, conj, word);
// fixedPoints(ctx, word, p[6]);
// conjugate_word("bca baca cab acab acb", modifier, conj, word);
// fixedPoints(ctx, word, p[7]);
LOOP(j) l[0][j] = cross(p[0][(3-j)%3], p[0][(4-j)%3]); LOOP(j) l[0][j] = cross(p[0][(3-j)%3], p[0][(4-j)%3]);
LOOP(j) l[1][j] = cross(p[1][(3-j)%3], p[1][(4-j)%3]); LOOP(j) l[1][j] = cross(p[1][(3-j)%3], p[1][(4-j)%3]);
LOOP(j) l[10][j] = cross(p[10][(3-j)%3], p[10][(4-j)%3]); LOOP(j) l[10][j] = cross(p[10][(3-j)%3], p[10][(4-j)%3]);
@ -679,68 +704,233 @@ void drawCurvedBox(DrawingContext *ctx, int base, const char *conj, int style)
} }
} }
groupelement_t *left(const char *word, groupelement_t *g)
{
int n = strlen(word);
for(int i = n-1; i >= 0; i--) {
if(word[i] == ' ')
continue;
g = g->adj[word[i]-'a'];
if(!g)
break;
}
return g;
}
void drawBoxes(DrawingContext *ctx) void drawBoxes(DrawingContext *ctx)
{ {
gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix *tmp = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
gsl_matrix *frame = getTempMatrix(ctx->ws); gsl_matrix *frame = getTempMatrix(ctx->ws);
gsl_matrix *frame2 = getTempMatrix(ctx->ws);
gsl_vector *startpoint_drawbasis = getTempVector(ctx->ws);
gsl_vector *startpoint_globalbasis = getTempVector(ctx->ws);
gsl_matrix **elements = getTempMatrices(ctx->ws, ctx->n_group_elements);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
cairo_save(C); cairo_save(C);
vector_t p[22][3];
vector_t l[22][3];
vector_t alpha[6];
vector_t ptmp[3];
char word[100], word2[100];
fixedPoints(ctx, "abc", p[0]);
fixedPoints(ctx, "bca", p[1]);
fixedPoints(ctx, "cab", p[2]);
fixedPoints(ctx, "bacabab", p[3]);
fixedPoints(ctx, "bcacabacb", p[4]);
cairo_set_line_width(C, 2.0/ctx->dim->scalefactor); cairo_set_line_width(C, 2.0/ctx->dim->scalefactor);
cairo_set_source_rgb(C, 0.6, 0.6, 0.6); cairo_set_source_rgb(C, 0.6, 0.6, 0.6);
drawRotationOrbit(ctx, "ab", p[0][0]); vector_t p[22][3];
drawRotationOrbit(ctx, "bc", p[0][0]); vector_t fp[3];
drawRotationOrbit(ctx, "ca", p[0][0]); vector_t l[22][3];
vector_t alpha[6];
vector_t ptmp[3];
vector_t start;
vector_t start2;
char word[100], word2[100];
if(ctx->mode >= 2) { fixedPoints(ctx, "cba", p[0]);
drawRotationOrbit(ctx, "bcabcb", p[1][0]); // bcC fixedPoints(ctx, "acb", p[1]);
drawRotationOrbit(ctx, "abcabcba", p[0][0]); // abcC fixedPoints(ctx, "bac", p[2]);
initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(elements[0]);
for(int i = 1; i < ctx->n_group_elements; i++) {
if(ctx->group[i].length % 2)
continue;
int letter = ROTATION_LETTER(ctx->group[i].letter, ctx->group[i].parent->letter);
multiply(gen[letter], elements[ctx->group[i].parent->parent->id], elements[i]);
} }
cairo_set_source_rgb(C, 0, 0, 0); gsl_vector_set(startpoint_drawbasis, 0, ctx->marking.x);
fixedPoints(ctx, "abababcbaba", p[3]); gsl_vector_set(startpoint_drawbasis, 1, ctx->marking.y);
gsl_vector_set(startpoint_drawbasis, 2, 1);
solve(ctx->cob, startpoint_drawbasis, startpoint_globalbasis, ctx->ws);
LOOP(i) start.x[i] = gsl_vector_get(startpoint_globalbasis, i);
cairo_set_source_rgb(C, 0, 0, 1); /*
fixedPoints(ctx, "bc bca cb", p[3]); fixedPoints(ctx, "ABAB", fp);
drawCovector(ctx, cross(fp[0], fp[2]));
drawVector(ctx, fp[1]);
computeRotationMatrixFrame(ctx, frame, "c");
drawRotationOrbit(ctx, "c", start); // ba cb ab ac = C A c B
drawVector(ctx, start);
computeMatrix(ctx, tmp, "ABABc");
start2 = apply(tmp, start);
computeRotationMatrixFrame(ctx, frame, "c");
multiply(tmp, frame, frame2);
drawVector(ctx, start2);
drawRotationOrbitFrame(ctx, frame2, apply(tmp, start));
computeMatrix(ctx, tmp, "ABABcABABC");
start2 = apply(tmp, start);
computeRotationMatrixFrame(ctx, frame, "c");
multiply(tmp, frame, frame2);
drawVector(ctx, start2);
drawRotationOrbitFrame(ctx, frame2, apply(tmp, start));
*/
for(groupelement_t *cur = &ctx->group[180]; cur->parent; cur = cur->parent)
fputc('a'+cur->letter, stdout);
fputc('\n', stdout);
queue_t queue;
queue_init(&queue);
queue_put(&queue, 0);
int current;
groupelement_t *cur, *next;
for(int i = 0; i < ctx->n_group_elements_combinatorial; i++)
ctx->group[i].visited = 0;
cur = &ctx->group[0];
computeRotationMatrixFrame(ctx, frame, "c");
for(int i = 0; i < 1000; i++) {
if(ctx->group[i].length % 2 != 0)
continue;
multiply(elements[i], frame, frame2);
drawRotationOrbitFrame(ctx, frame2, apply(elements[i], start));
}
/*
while((current = queue_get(&queue)) != -1) {
cur = &ctx->group[current];
if(cur->visited > 4)
continue;
if(cur->id < ctx->n_group_elements) {
multiply(elements[cur->id], frame, frame2);
drawRotationOrbitFrame(ctx, frame2, apply(elements[cur->id], start));
}
next = left("ab ab", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
next = left("cbac cbac", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
next = left("cacbca cacbca", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
next = left("cabcacbcac cabcacbcac", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
next = left("acbcacba acbcacba", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
next = left("bcacbc bcacbc", cur);
if(next && next->visited == 0) {
queue_put(&queue, next->id);
next->visited = cur->visited+1;
}
}
*/
// drawRotationOrbit(ctx, "a", p[1][0]);
// drawRotationOrbit(ctx, "b", p[2][0]);
cairo_restore(C); cairo_restore(C);
releaseTempMatrices(ctx->ws, 5); releaseTempMatrices(ctx->ws, 9 + ctx->n_group_elements);
releaseTempVectors(ctx->ws, 2);
} }
void drawBoxes2(DrawingContext *ctx) void drawBoxes2(DrawingContext *ctx)
{ {
gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix *rot = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
cairo_save(C); cairo_save(C);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
vector_t p[4][3]; vector_t p[4][3];
fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "cba", p[0]);
fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "acb", p[1]);
fixedPoints(ctx, "cab", p[2]); fixedPoints(ctx, "bac", p[2]);
cairo_set_line_width(C, 2.5/ctx->dim->scalefactor); cairo_set_line_width(C, 2.5/ctx->dim->scalefactor);
/*
cairo_set_source_rgb(C, 0, 1, 1);
fixedPoints(ctx, "abc", p[0]);
drawRotationOrbit(ctx, "bc", p[0][0]); // (r^{-1}a)^2 C / cbr
fixedPoints(ctx, "bca", p[0]);
drawRotationOrbit(ctx, "abca", p[0][0]); // (r^{-1}a)^2 C / cbr
cairo_set_source_rgb(C, 1, 1, 0);
fixedPoints(ctx, "abc", p[0]);
drawRotationOrbit(ctx, "cbcabc", p[0][0]); // (r^{-1}a)^4 C / cbac r-
fixedPoints(ctx, "bca", p[0]);
drawRotationOrbit(ctx, "acbcabca", p[0][0]); // (r^{-1}a)^4 C / cbac r-
cairo_set_source_rgb(C, 1, 0, 1);
fixedPoints(ctx, "abc", p[0]);
drawRotationOrbit(ctx, "cbacabcabc", p[0][0]); // (r^{-1}a)^6 C / cbacba
fixedPoints(ctx, "bca", p[0]);
drawRotationOrbit(ctx, "acbacabcabca", p[0][0]); // (r^{-1}a)^6 C / cbacba
*/
/*
cairo_set_source_rgb(C, 1, 0, 0);
fixedPoints(ctx, "bca", p[3]);
drawRotationOrbit(ctx, "bcabcb", p[3][0]); // cb c a bc
fixedPoints(ctx, "abc", p[3]);
drawRotationOrbit(ctx, "abcabcba", p[3][0]); // cb c a bc
cairo_set_source_rgb(C, 0, 1, 0);
fixedPoints(ctx, "ababcba", p[3]);
drawRotationOrbit(ctx, "ababcababa", p[3][0]); // cb c a bc
fixedPoints(ctx, "abc", p[3]);
drawRotationOrbit(ctx, "abcabcabacba", p[3][0]); // cb c a bc
*/
// drawRotationOrbit(ctx, "bc", p[3][0]);
cairo_set_source_rgb(C, 0, 0, 0); cairo_set_source_rgb(C, 0, 0, 0);
drawCurvedBox(ctx, 'A', "", 2); drawCurvedBox(ctx, 'A', "", 2);
cairo_set_source_rgb(C, 0, 0, 1);
// drawCurvedBox(ctx, 'C', "ab", 2);
// drawCurvedBox(ctx, 'C', "ab", 2);
// drawCurvedBox(ctx, 'B', "bca", 2);
// drawCurvedBox(ctx, 'B', "ba", 2);
// drawCurvedBox(ctx, 'B', "bca", 2);
// drawCurvedBox(ctx, 'B', "abca", 2);
// drawCurvedBox(ctx, 'C', "abab", 2);
// drawCurvedBox(ctx, 'C', "ababab", 2);
if(ctx->mode >= 3 && ctx->mode != 4) { if(ctx->mode >= 3 && ctx->mode != 4) {
cairo_set_source_rgb(C, 0, 0, 0); cairo_set_source_rgb(C, 0, 0, 0);
drawCurvedBox(ctx, 'B', "", 2); drawCurvedBox(ctx, 'B', "", 2);
@ -756,11 +946,15 @@ void drawBoxes2(DrawingContext *ctx)
drawCurvedBox(ctx, 'A', "bcbcbcbc", 2); drawCurvedBox(ctx, 'A', "bcbcbcbc", 2);
drawCurvedBox(ctx, 'A', "bcbcbcbcbc", 2); drawCurvedBox(ctx, 'A', "bcbcbcbcbc", 2);
drawCurvedBox(ctx, 'A', "bcbcbcbcbcbc", 2); drawCurvedBox(ctx, 'A', "bcbcbcbcbcbc", 2);
// drawCurvedBox(ctx, 'A', "b", 2);
// drawCurvedBox(ctx, 'A', "bcb", 2);
// drawCurvedBox(ctx, 'A', "bcbcb", 2);
// drawCurvedBox(ctx, 'A', "bcbcbcb", 2);
// drawCurvedBox(ctx, 'A', "bcbcbcbcb", 2);
} }
if(ctx->mode == 6) { if(ctx->mode == 6) {
cairo_set_source_rgb(C, 0, 0.8, 0.5); cairo_set_source_rgb(C, 0, 0.8, 0.5);
drawCurvedBox(ctx, 'C', "ababab", 2);
drawCurvedBox(ctx, 'C', "abababab", 2); drawCurvedBox(ctx, 'C', "abababab", 2);
drawCurvedBox(ctx, 'C', "ababababab", 2); drawCurvedBox(ctx, 'C', "ababababab", 2);
} }
@ -769,45 +963,291 @@ void drawBoxes2(DrawingContext *ctx)
cairo_set_source_rgb(C, 0, 0.8, 0.5); cairo_set_source_rgb(C, 0, 0.8, 0.5);
drawCurvedBox(ctx, 'C', "ab", 2); drawCurvedBox(ctx, 'C', "ab", 2);
drawCurvedBox(ctx, 'C', "abab", 2); drawCurvedBox(ctx, 'C', "abab", 2);
drawCurvedBox(ctx, 'C', "ababab", 2);
} }
if(ctx->mode >= 8) { if(ctx->mode >= 8) {
cairo_set_source_rgb(C, 0, 0.8, 0.5); cairo_set_source_rgb(C, 0, 0.8, 0.5);
drawCurvedBox(ctx, 'C', "b", 2); drawCurvedBox(ctx, 'C', "b", 2);
drawCurvedBox(ctx, 'C', "bab", 2); drawCurvedBox(ctx, 'C', "bab", 2);
drawCurvedBox(ctx, 'C', "babab", 2);
} }
if(ctx->mode >= 9) { if(ctx->mode >= 9) {
cairo_set_source_rgb(C, 0.8, 0, 0.5); cairo_set_source_rgb(C, 0.8, 0, 0.5);
drawCurvedBox(ctx, 'B', "abca", 2); drawCurvedBox(ctx, 'B', "abca", 2);
drawCurvedBox(ctx, 'B', "abcaca", 2); drawCurvedBox(ctx, 'B', "abcaca", 2);
drawCurvedBox(ctx, 'B', "aba", 2); drawCurvedBox(ctx, 'B', "abcacaca", 2);
drawCurvedBox(ctx, 'B', "abaca", 2); drawCurvedBox(ctx, 'B', "aba", 2);
drawCurvedBox(ctx, 'B', "abaca", 2);
drawCurvedBox(ctx, 'B', "abacaca", 2);
drawCurvedBox(ctx, 'B', "ababca", 2); drawCurvedBox(ctx, 'B', "ababca", 2);
drawCurvedBox(ctx, 'B', "ababcaca", 2); drawCurvedBox(ctx, 'B', "ababcaca", 2);
drawCurvedBox(ctx, 'B', "ababa", 2); drawCurvedBox(ctx, 'B', "ababcacaca", 2);
drawCurvedBox(ctx, 'B', "ababaca", 2); drawCurvedBox(ctx, 'B', "ababa", 2);
drawCurvedBox(ctx, 'B', "ababaca", 2);
drawCurvedBox(ctx, 'B', "ababacaca", 2);
drawCurvedBox(ctx, 'B', "bca", 2); drawCurvedBox(ctx, 'B', "abababca", 2);
drawCurvedBox(ctx, 'B', "bcaca", 2); drawCurvedBox(ctx, 'B', "abababcaca", 2);
drawCurvedBox(ctx, 'B', "ba", 2); drawCurvedBox(ctx, 'B', "abababcacaca", 2);
drawCurvedBox(ctx, 'B', "baca", 2); drawCurvedBox(ctx, 'B', "abababa", 2);
drawCurvedBox(ctx, 'B', "abababaca", 2);
drawCurvedBox(ctx, 'B', "abababacaca", 2);
drawCurvedBox(ctx, 'B', "babca", 2); drawCurvedBox(ctx, 'B', "bca", 2);
drawCurvedBox(ctx, 'B', "babcaca", 2); drawCurvedBox(ctx, 'B', "bcaca", 2);
drawCurvedBox(ctx, 'B', "baba", 2); drawCurvedBox(ctx, 'B', "bcacaca", 2);
drawCurvedBox(ctx, 'B', "babaca", 2); drawCurvedBox(ctx, 'B', "ba", 2);
drawCurvedBox(ctx, 'B', "baca", 2);
drawCurvedBox(ctx, 'B', "bacaca", 2);
cairo_restore(C); drawCurvedBox(ctx, 'B', "babca", 2);
releaseTempMatrices(ctx->ws, 4); drawCurvedBox(ctx, 'B', "babcaca", 2);
drawCurvedBox(ctx, 'B', "babcacaca", 2);
drawCurvedBox(ctx, 'B', "baba", 2);
drawCurvedBox(ctx, 'B', "babaca", 2);
drawCurvedBox(ctx, 'B', "babacaca", 2);
drawCurvedBox(ctx, 'B', "bababca", 2);
drawCurvedBox(ctx, 'B', "bababcaca", 2);
drawCurvedBox(ctx, 'B', "bababcacaca", 2);
drawCurvedBox(ctx, 'B', "bababa", 2);
drawCurvedBox(ctx, 'B', "bababaca", 2);
drawCurvedBox(ctx, 'B', "bababacaca", 2);
} }
// drawCurvedBox(ctx, 'B', "abab", 2);
// drawCurvedBox(ctx, 'B', "ababab", 2);
// drawCurvedBox(ctx, 'C', "b", 1);
// drawCurvedBox(ctx, 'C', "ababab");
// drawCurvedBox(ctx, 'C', "abababab");
// drawCurvedBox(ctx, 'C', "b");
// drawCurvedBox(ctx, 'C', "bab");
// drawCurvedBox(ctx, 'C', "babab");
// drawCurvedBox(ctx, 'C', "abababab");
// drawCurvedBox(ctx, 'C', "ababababab");
// drawCurvedBox(ctx, 'C', "abababababab");
cairo_set_source_rgb(C, 0, 0, 1);
// drawCurvedBox(ctx, 'B', "abca", 1);
// drawCurvedBox(ctx, 'B', "aba", 1);
// drawCurvedBox(ctx, 'B', "bca", 1);
// drawCurvedBox(ctx, 'B', "ba", 1);
// drawCurvedBox(ctx, 'B', "abaca");
// drawCurvedBox(ctx, 'B', "abcaca");
// drawCurvedBox(ctx, 'B', "abaca");
// drawCurvedBox(ctx, 'B', "aba");
// drawCurvedBox(ctx, 'B', "ababca");
// drawCurvedBox(ctx, 'B', "ababa");
// drawCurvedBox(ctx, 'B', "abababca");
// drawCurvedBox(ctx, 'B', "abababa");
// drawCurvedBox(ctx, 'B', "bca");
// drawCurvedBox(ctx, 'B', "ba");
// drawCurvedBox(ctx, 'B', "babca");
// drawCurvedBox(ctx, 'B', "baba");
// drawCurvedBox(ctx, 'B', "bababca");
// drawCurvedBox(ctx, 'B', "bababa");
cairo_set_source_rgb(C, 1, 0, 1);
// drawCurvedBox(ctx, 'A', "abcac");
// drawCurvedBox(ctx, 'A', "bcac");
// drawCurvedBox(ctx, 'A', "abcacbc");
// drawCurvedBox(ctx, 'A', "abcac");
// drawCurvedBox(ctx, 'A', "abcacbc");
// drawCurvedBox(ctx, 'A', "ababc");
// drawCurvedBox(ctx, 'A', "ababcbc");
/* drawCurvedBox(ctx, 'A', "abcac");
drawCurvedBox(ctx, 'A', "ababc");
drawCurvedBox(ctx, 'A', "abac");
drawCurvedBox(ctx, 'A', "ababcabc");
drawCurvedBox(ctx, 'A', "ababcac");
drawCurvedBox(ctx, 'A', "abababc");
drawCurvedBox(ctx, 'A', "ababac");
drawCurvedBox(ctx, 'A', "abababcabc");
drawCurvedBox(ctx, 'A', "abababcac");
drawCurvedBox(ctx, 'A', "ababababc");
drawCurvedBox(ctx, 'A', "abababac");
drawCurvedBox(ctx, 'A', "bcabc");
drawCurvedBox(ctx, 'A', "bcac");
drawCurvedBox(ctx, 'A', "babc");
drawCurvedBox(ctx, 'A', "bac");
drawCurvedBox(ctx, 'A', "babcabc");
drawCurvedBox(ctx, 'A', "babcac");
drawCurvedBox(ctx, 'A', "bababc");
drawCurvedBox(ctx, 'A', "babac");
drawCurvedBox(ctx, 'A', "bababcabc");
drawCurvedBox(ctx, 'A', "bababcac");
drawCurvedBox(ctx, 'A', "babababc");
drawCurvedBox(ctx, 'A', "bababac");
*/
// drawCurvedBox(ctx, 'A', "ababc");
cairo_set_source_rgb(C, 1, 0.5, 0);
// drawCurvedBox(ctx, 'C', "abcabcab");
// drawCurvedBox(ctx, 'B', "bca");
// drawCurvedBox(ctx, 'B', "abcacaca");
// drawCurvedBox(ctx, 'B', "abaca");
// drawCurvedBox(ctx, 'B', "aba");
// drawCurvedBox(ctx, 'B', "aba");
// drawCurvedBox(ctx, 'B', "abcaca");
// drawCurvedBox(ctx, 'B', "aba");
// drawCurvedBox(ctx, 'B', "abaca");
cairo_set_source_rgb(C, 0, 0, 1);
// drawCurvedBox(ctx, 'A', "abcabc");
// drawCurvedBox(ctx, 'A', "abcabcbc");
// drawCurvedBox(ctx, 'A', "abcacbc");
// drawCurvedBox(ctx, 'A', "abcac");
// drawCurvedBox(ctx, 'A', "bcabc");
// drawCurvedBox(ctx, 'A', "bcabcbc");
// drawCurvedBox(ctx, 'A', "bcacbc");
// drawCurvedBox(ctx, 'A', "bcac");
// drawCurvedBox(ctx, 'A', "abcac");
// drawCurvedBox(ctx, 'A', "abcac");
// drawCurvedBox(ctx, 'A', "abcacbc");
// drawCurvedBox(ctx, 'B', "abacaca");
// drawCurvedBox(ctx, 'B', "abacacaca");
cairo_set_source_rgb(C, 0, 1, 1);
fixedPoints(ctx, "ababcba", p[0]);
// drawRotationOrbit(ctx, "abcaba", p[0][0]);
/*
int p = 9;
vector_t fp[3][3],neutral_line[3],reflection_line[p],star[2*p],outer[2];
vector_t rotation_line = {0,0,1};
cairo_set_line_width(C, 1.5/ctx->dim->scalefactor);
cairo_set_source_rgb(C, 1, 0, 0);
multiply(gen[0], gen[1], rot);
fixedPoints(ctx, "abc", fp[0]);
fixedPoints(ctx, "bca", fp[1]);
fixedPoints(ctx, "cab", fp[2]);
LOOP(i) neutral_line[i] = cross(fp[i][0], fp[i][2]);
LOOP(j) reflection_line[0].x[j] = gsl_matrix_get(ctx->cartan, 0, j);
star[0] = cross(neutral_line[0],reflection_line[0]);
star[p] = cross(neutral_line[2],reflection_line[0]);
for(int j = 1; j < p; j++) {
reflection_line[j] = apply_transpose(rot, reflection_line[j-1]);
star[j] = apply(rot, star[j-1]);
star[j+p] = apply(rot, star[j+p-1]);
}
outer[0] = cross(neutral_line[0],reflection_line[5]);
outer[1] = cross(neutral_line[2],reflection_line[5]);
for(int j = 0; j < 8; j++) {
drawVector(ctx, star[j]);
drawVector(ctx, star[p+j]);
}
for(int j = 0; j < 7; j++) {
// if(j == 3)
// continue;
drawSegment(ctx, star[j%p], star[(j+1)%p+p]);
drawSegment(ctx, star[(j+1)%p+p], star[(j+1)%p]);
drawSegment(ctx, star[(j+1)%p], star[j%p+p]);
drawSegment(ctx, star[j%p+p], star[j%p]);
}
cairo_set_source_rgb(C, 0, 0, 1);
drawVector(ctx,outer[0]);
drawVector(ctx,outer[1]);
// drawCovector(ctx, neutral_line[0]);
// drawCovector(ctx, neutral_line[2]);
drawSegment(ctx, star[0], star[p]);
drawSegment(ctx, star[p], outer[1]);
drawSegment(ctx, outer[1], outer[0]);
drawSegment(ctx, outer[0], star[0]);
cairo_set_source_rgb(C, 0, 0, 0);
drawCovector(ctx, rotation_line);
*/
// for(int j = 0; j < 5; j++)
// drawCovector(ctx, reflection_line[j]);
// 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, 1, 4, p[0][0], i[0], p[1][0], i[1]);
// abc, ababcba, abababcbaba, ..., cab
// bca, acaba, abacababa, ..., babcb
/*
vector_t v[4][3];
vector_t i[4];
fixedPoints(ctx, "abc", v[0]);
fixedPoints(ctx, "bca", v[1]);
fixedPoints(ctx, "cab", v[2]);
fixedPoints(ctx, "acaba", v[3]);
i[0] = cross(cross(v[0][1],v[0][2]),cross(v[2][0],v[2][2]));
i[1] = cross(cross(v[1][1],v[1][2]),cross(v[3][0],v[3][2]));
i[2] = cross(cross(v[2][0],v[2][2]),cross(v[3][0],v[3][2]));
i[3] = cross(cross(v[0][0],v[0][2]),cross(v[1][0],v[1][2]));
// cairo_set_source_rgb(C, 0, 0, 1);
// drawPolygon(ctx, 1, 6, v[2][2], v[1][1], v[0][1], v[3][2], v[3][1], v[2][1]);
// drawPolygon(ctx, 1, 6, v[1][2], i[1], i[2], i[0], v[0][2], i[3]);
cairo_set_line_width(C, 1.5/ctx->dim->scalefactor);
cairo_set_source_rgb(C, 1, 0, 0);
// drawBox(ctx, "bca", "abc");
drawCurvedBox(ctx, 'A', "");
*/
/*
cairo_set_source_rgb(C, 1, 0.5, 0);
drawBox(ctx, "ab abc ba", "ab cab ba");
drawBox(ctx, "abab abc baba", "abab cab baba");
drawBox(ctx, "ababab abc bababa", "ababab cab bababa");
drawBox(ctx, "abababab abc babababa", "abababab cab babababa");
// drawBox(ctx, "ababababab abc bababababa", "ababababab cab bababababa");
drawBox(ctx, "b abc b", "b cab b");
drawBox(ctx, "bab abc bab", "bab cab bab");
drawBox(ctx, "babab abc babab", "babab cab babab");
drawBox(ctx, "bababab abc bababab", "bababab cab bababab");
// drawBox(ctx, "babababab abc babababab", "babababab cab babababab");
*/
cairo_restore(C);
releaseTempMatrices(ctx->ws, 7);
} }
void drawRotatedReflectors(DrawingContext *ctx) void drawRotatedReflectors(DrawingContext *ctx)
{ {
gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix *rot = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
cairo_t *C = ctx->cairo; cairo_t *C = ctx->cairo;
vector_t fp[3], fp2[3]; vector_t fp[3], fp2[3];
vector_t w; vector_t w;
@ -815,7 +1255,7 @@ void drawRotatedReflectors(DrawingContext *ctx)
cairo_set_source_rgb(C, 0.7, 0.7, 0.7); cairo_set_source_rgb(C, 0.7, 0.7, 0.7);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
multiply(gen[0], gen[1], rot); multiply(gen[0], gen[1], rot);
@ -836,7 +1276,7 @@ void drawRotatedReflectors(DrawingContext *ctx)
fixedPoints(ctx, "cacabac", fp2); fixedPoints(ctx, "cacabac", fp2);
drawRotationOrbit(ctx, "ac", fp[0]); drawRotationOrbit(ctx, "ac", fp[0]);
releaseTempMatrices(ctx->ws, 4); releaseTempMatrices(ctx->ws, 7);
} }
void drawDualLimitCurve(DrawingContext *ctx) void drawDualLimitCurve(DrawingContext *ctx)
@ -846,12 +1286,36 @@ void drawDualLimitCurve(DrawingContext *ctx)
cairo_save(C); cairo_save(C);
cairo_set_source_rgb(C, 0.5, 0.5, 1); cairo_set_source_rgb(C, 0.5, 0.5, 1);
int n = 18; gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
vector_t p[n][3]; gsl_matrix **elements = getTempMatrices(ctx->ws, ctx->n_group_elements);
vector_t l[n][3];
vector_t ptmp[3], ltmp[3];
fixedPoints(ctx, "abc", p[0]); // wordEigenvalues(ctx, "abc", ev);
// LOOP(i) LOOP(j) gsl_matrix_set(coxeter_fixedpoints, j, i, cox[0][i].x[j]);
initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(elements[0]);
for(int i = 1; i < ctx->n_group_elements; i++)
multiply(gen[ctx->group[i].letter], elements[ctx->group[i].parent->id], elements[i]);
vector_t p[3], l[3], v;
fixedPoints(ctx, "cba", p);
drawVector(ctx, p[0]);
drawVector(ctx, p[1]);
drawVector(ctx, p[2]);
LOOP(i) l[i] = cross(p[(i+1)%3], p[(i+2)%3]);
for(int i = 0; i < ctx->n_group_elements; i++) {
v = apply_transpose(elements[i], l[0]);
drawCovector(ctx, v);
}
releaseTempMatrices(ctx->ws, 3 + ctx->n_group_elements);
// releaseTempVectors(ctx->ws, 4);
/*
fixedPoints(ctx, "ab abc ba", p[1]); fixedPoints(ctx, "ab abc ba", p[1]);
fixedPoints(ctx, "abab abc baba", p[2]); fixedPoints(ctx, "abab abc baba", p[2]);
fixedPoints(ctx, "ababab abc bababa", p[3]); fixedPoints(ctx, "ababab abc bababa", p[3]);
@ -870,6 +1334,7 @@ void drawDualLimitCurve(DrawingContext *ctx)
fixedPoints(ctx, "bababa bca ababab", p[15]); fixedPoints(ctx, "bababa bca ababab", p[15]);
fixedPoints(ctx, "baba bca abab", p[16]); fixedPoints(ctx, "baba bca abab", p[16]);
fixedPoints(ctx, "ba bca ab", p[17]); fixedPoints(ctx, "ba bca ab", p[17]);
*/
/* /*
fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "abc", p[0]);
@ -907,6 +1372,7 @@ void drawDualLimitCurve(DrawingContext *ctx)
// drawCovector(ctx, l[i][2]); // drawCovector(ctx, l[i][2]);
}*/ }*/
/*
fixedPoints(ctx, "abc", ptmp); fixedPoints(ctx, "abc", ptmp);
drawCovector(ctx, cross(ptmp[0], ptmp[1])); drawCovector(ctx, cross(ptmp[0], ptmp[1]));
fixedPoints(ctx, "bca", ptmp); fixedPoints(ctx, "bca", ptmp);
@ -919,6 +1385,7 @@ void drawDualLimitCurve(DrawingContext *ctx)
drawCovector(ctx, cross(ptmp[0], ptmp[1])); drawCovector(ctx, cross(ptmp[0], ptmp[1]));
fixedPoints(ctx, "acaba", ptmp); fixedPoints(ctx, "acaba", ptmp);
drawCovector(ctx, cross(ptmp[0], ptmp[1])); drawCovector(ctx, cross(ptmp[0], ptmp[1]));
*/
cairo_restore(C); cairo_restore(C);
} }
@ -974,7 +1441,7 @@ void drawLimitCurve(DrawingContext *ctx)
void drawCoxeterOrbit(DrawingContext *ctx) void drawCoxeterOrbit(DrawingContext *ctx)
{ {
gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix *rot = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
gsl_vector *eval = getTempVector(ctx->ws); gsl_vector *eval = getTempVector(ctx->ws);
gsl_matrix *coxeter_fixedpoints = getTempMatrix(ctx->ws); gsl_matrix *coxeter_fixedpoints = getTempMatrix(ctx->ws);
gsl_vector *startpoint_coxeterbasis = getTempVector(ctx->ws); gsl_vector *startpoint_coxeterbasis = getTempVector(ctx->ws);
@ -991,7 +1458,7 @@ void drawCoxeterOrbit(DrawingContext *ctx)
int first = 1; int first = 1;
cairo_save(C); cairo_save(C);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
cairo_set_source_rgb(C, 0, 0, 1); cairo_set_source_rgb(C, 0, 0, 1);
@ -1002,7 +1469,7 @@ void drawCoxeterOrbit(DrawingContext *ctx)
wordEigenvalues(ctx, "abc", ev); wordEigenvalues(ctx, "abc", ev);
LOOP(i) LOOP(j) gsl_matrix_set(coxeter_fixedpoints, j, i, cox[0][i].x[j]); LOOP(i) LOOP(j) gsl_matrix_set(coxeter_fixedpoints, j, i, cox[0][i].x[j]);
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(elements[0]); gsl_matrix_set_identity(elements[0]);
for(int i = 1; i < ctx->n_group_elements; i++) for(int i = 1; i < ctx->n_group_elements; i++)
multiply(gen[ctx->group[i].letter], elements[ctx->group[i].parent->id], elements[i]); multiply(gen[ctx->group[i].letter], elements[ctx->group[i].parent->id], elements[i]);
@ -1016,7 +1483,7 @@ void drawCoxeterOrbit(DrawingContext *ctx)
gsl_vector_set(startpoint_drawbasis, 2, 1); gsl_vector_set(startpoint_drawbasis, 2, 1);
solve(ctx->cob, startpoint_drawbasis, startpoint_globalbasis, ctx->ws); solve(ctx->cob, startpoint_drawbasis, startpoint_globalbasis, ctx->ws);
solve(coxeter_fixedpoints, startpoint_globalbasis, startpoint_coxeterbasis, ctx->ws); // solve(coxeter_fixedpoints, startpoint_globalbasis, startpoint_coxeterbasis, ctx->ws);
// LOOP(i) start.x[i] = gsl_vector_get(startpoint_coxeterbasis, i); // LOOP(i) start.x[i] = gsl_vector_get(startpoint_coxeterbasis, i);
LOOP(i) start.x[i] = gsl_vector_get(startpoint_globalbasis, i); LOOP(i) start.x[i] = gsl_vector_get(startpoint_globalbasis, i);
@ -1056,7 +1523,7 @@ void drawCoxeterOrbit(DrawingContext *ctx)
// LOOP(i) drawVector(ctx, abcb[i]); // LOOP(i) drawVector(ctx, abcb[i]);
cairo_restore(C); cairo_restore(C);
releaseTempMatrices(ctx->ws, 5 + ctx->n_group_elements); releaseTempMatrices(ctx->ws, 8 + ctx->n_group_elements);
releaseTempVectors(ctx->ws, 4); releaseTempVectors(ctx->ws, 4);
} }
@ -1065,7 +1532,7 @@ void drawText(DrawingContext *ctx)
cairo_move_to(ctx->cairo, 15, 30); cairo_move_to(ctx->cairo, 15, 30);
cairo_set_source_rgb(ctx->cairo, 0, 0, 0); cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
char buf[100]; char buf[100];
sprintf(buf, "t = exp(%.8f) = %.8f, marking = (%.5f, %.5f)", log(ctx->parameter), ctx->parameter, ctx->marking.x, ctx->marking.y); sprintf(buf, "t = exp(%.8f) = %.8f, s = exp(%.8f) = %.8f, marking = (%.5f, %.5f)", log(ctx->parameter), ctx->parameter, log(ctx->parameter2), ctx->parameter2, ctx->marking.x, ctx->marking.y);
cairo_show_text(ctx->cairo, buf); cairo_show_text(ctx->cairo, buf);
} }
@ -1111,6 +1578,7 @@ void draw(DrawingContext *ctx)
if(ctx->show_marking) if(ctx->show_marking)
{ {
cairo_set_source_rgb(C, 0, 0, 1); cairo_set_source_rgb(C, 0, 0, 1);
drawPoint(ctx, ctx->marking);
} }
if(ctx->show_coxeter_orbit) if(ctx->show_coxeter_orbit)
@ -1120,7 +1588,7 @@ void draw(DrawingContext *ctx)
cairo_identity_matrix(C); // text is in screen coordinates cairo_identity_matrix(C); // text is in screen coordinates
if(ctx->show_text) if(ctx->show_text)
drawText(ctx); drawText(ctx);
cairo_surface_flush(cairo_get_target(C)); cairo_surface_flush(cairo_get_target(C));
} }

View File

@ -5,6 +5,7 @@ static int compareAngle(const void *x, const void *y)
return ((double*)x)[2] > ((double*)y)[2] ? 1 : -1; return ((double*)x)[2] > ((double*)y)[2] ? 1 : -1;
} }
// might need a rewrite
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s) void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s)
{ {
gsl_matrix_set(cartan, 0, 0, 2); gsl_matrix_set(cartan, 0, 0, 2);
@ -20,11 +21,58 @@ void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s)
gsl_matrix_set(cartan, 2, 2, 2); gsl_matrix_set(cartan, 2, 2, 2);
} }
void initializeTriangleGenerators(gsl_matrix **gen, gsl_matrix *cartan) void initializeTriangleGenerators(gsl_matrix **gen, double a1, double a2, double a3, double s, double t, workspace_t *ws)
{ {
LOOP(i) gsl_matrix_set_identity(gen[i]); gsl_matrix *reflection_gen[3];
LOOP(i) LOOP(j) *gsl_matrix_ptr(gen[i], j, j) = -1.0;
LOOP(i) LOOP(j) *gsl_matrix_ptr(gen[i], i, j) += gsl_matrix_get(cartan, i, j); LOOP(i) {
reflection_gen[i] = gsl_matrix_alloc(3, 3);
gsl_matrix_set_identity(reflection_gen[i]);
}
double rho[3];
rho[0] = sqrt(s*s + 2*s*cos(a1) + 1);
rho[1] = sqrt(s*s + 2*s*cos(a2) + 1);
rho[2] = sqrt(s*s + 2*s*cos(a3) + 1);
gsl_matrix_set(reflection_gen[0], 0, 0, -1.0);
gsl_matrix_set(reflection_gen[0], 0, 1, rho[2]*t);
gsl_matrix_set(reflection_gen[0], 0, 2, rho[1]/t);
gsl_matrix_set(reflection_gen[1], 1, 0, rho[2]/t);
gsl_matrix_set(reflection_gen[1], 1, 1, -1.0);
gsl_matrix_set(reflection_gen[1], 1, 2, rho[0]*t);
gsl_matrix_set(reflection_gen[2], 2, 0, rho[1]*t);
gsl_matrix_set(reflection_gen[2], 2, 1, rho[0]/t);
gsl_matrix_set(reflection_gen[2], 2, 2, -1.0);
LOOP(i) {
gsl_matrix_set_identity(gen[i]);
gsl_matrix_set(gen[i], (i+1)%3, (i+1)%3, s);
gsl_matrix_set(gen[i], (i+2)%3, (i+2)%3, 1/s);
gsl_matrix_set_identity(gen[i+3]);
gsl_matrix_set(gen[i+3], (i+1)%3, (i+1)%3, 1/s);
gsl_matrix_set(gen[i+3], (i+2)%3, (i+2)%3, s);
}
LOOP(i) {
multiply_left(reflection_gen[i], gen[(i+2)%3], ws);
multiply_right(gen[(i+2)%3], reflection_gen[(i+1)%3], ws);
multiply_left(reflection_gen[(i+1)%3], gen[(i+2)%3+3], ws);
multiply_right(gen[(i+2)%3+3], reflection_gen[i], ws);
}
LOOP(i) gsl_matrix_free(reflection_gen[i]);
}
void initializeTriangleGeneratorsCurrent(gsl_matrix **gen, DrawingContext *ctx)
{
double angle[3];
LOOP(i) angle[i] = 2*M_PI*ctx->k[i]/ctx->p[i];
initializeTriangleGenerators(gen, angle[0], angle[1], angle[2], ctx->parameter2, ctx->parameter, ctx->ws);
} }
int computeLimitCurve(DrawingContext *ctx) int computeLimitCurve(DrawingContext *ctx)
@ -38,7 +86,7 @@ int computeLimitCurve(DrawingContext *ctx)
gsl_matrix *coxeter = getTempMatrix(ctx->ws); gsl_matrix *coxeter = getTempMatrix(ctx->ws);
gsl_matrix *coxeter_fixedpoints = getTempMatrix(ctx->ws); gsl_matrix *coxeter_fixedpoints = getTempMatrix(ctx->ws);
gsl_matrix *fixedpoints = getTempMatrix(ctx->ws); gsl_matrix *fixedpoints = getTempMatrix(ctx->ws);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
gsl_matrix **elements = getTempMatrices(ctx->ws, ctx->n_group_elements); gsl_matrix **elements = getTempMatrices(ctx->ws, ctx->n_group_elements);
groupelement_t *group = ctx->group; groupelement_t *group = ctx->group;
int success = 0; int success = 0;
@ -50,31 +98,43 @@ int computeLimitCurve(DrawingContext *ctx)
// do first in the Fuchsian positive case to get the angles // 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); cartanMatrix(cartan_pos, M_PI/ctx->p[0], M_PI/ctx->p[1], M_PI/ctx->p[2], 1.0);
initializeTriangleGenerators(gen, cartan_pos); initializeTriangleGenerators(gen, 2*M_PI/ctx->p[0], 2*M_PI/ctx->p[1], 2*M_PI/ctx->p[2], 1.0, 1.0, ctx->ws);
gsl_matrix_set_identity(elements[0]); gsl_matrix_set_identity(elements[0]);
for(int i = 1; i < ctx->n_group_elements; i++) for(int i = 1; i < ctx->n_group_elements; i++) {
multiply(gen[group[i].letter], elements[group[i].parent->id], elements[i]); if(group[i].length % 2)
continue;
int letter = ROTATION_LETTER(group[i].letter, group[i].parent->letter);
multiply(gen[letter], elements[group[i].parent->parent->id], elements[i]);
}
diagonalize_symmetric_form(cartan_pos, cob_pos, ws); diagonalize_symmetric_form(cartan_pos, cob_pos, ws);
multiply_many(ws, coxeter_pos, 3, gen[0], gen[1], gen[2]); multiply_many(ws, coxeter_pos, 3, gen[2], gen[1], gen[0]);
int ev_count_pos = real_eigenvectors(coxeter_pos, coxeter_fixedpoints_pos, ws); int ev_count_pos = real_eigenvectors(coxeter_pos, coxeter_fixedpoints_pos, ws);
if(ev_count_pos != 3) if(ev_count_pos != 3)
goto error_out; goto error_out;
int n = 0;
for(int i = 0; i < ctx->n_group_elements; i++) { for(int i = 0; i < ctx->n_group_elements; i++) {
if(group[i].length % 2)
continue;
multiply_many(ws, fixedpoints_pos, 3, cob_pos, elements[i], coxeter_fixedpoints_pos); multiply_many(ws, fixedpoints_pos, 3, cob_pos, elements[i], coxeter_fixedpoints_pos);
ctx->limit_curve[3*i+2] = atan2( ctx->limit_curve[3*n+2] = atan2(
gsl_matrix_get(fixedpoints_pos, 2, column)/gsl_matrix_get(fixedpoints_pos, 0, column), gsl_matrix_get(fixedpoints_pos, 2, column)/gsl_matrix_get(fixedpoints_pos, 0, column),
gsl_matrix_get(fixedpoints_pos, 1, column)/gsl_matrix_get(fixedpoints_pos, 0, column)); gsl_matrix_get(fixedpoints_pos, 1, column)/gsl_matrix_get(fixedpoints_pos, 0, column));
n++;
} }
// now do it again to calculate x and y coordinates // now do it again to calculate x and y coordinates
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(elements[0]); gsl_matrix_set_identity(elements[0]);
for(int i = 1; i < ctx->n_group_elements; i++) for(int i = 1; i < ctx->n_group_elements; i++) {
multiply(gen[group[i].letter], elements[group[i].parent->id], elements[i]); if(group[i].length % 2)
continue;
int letter = ROTATION_LETTER(group[i].letter, group[i].parent->letter);
multiply(gen[letter], elements[group[i].parent->parent->id], elements[i]);
}
multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]); multiply_many(ws, coxeter, 3, gen[2], gen[1], gen[0]);
int ev_count = real_eigenvectors(coxeter, coxeter_fixedpoints, ws); int ev_count = real_eigenvectors(coxeter, coxeter_fixedpoints, ws);
if(ev_count == 1) if(ev_count == 1)
@ -82,11 +142,17 @@ int computeLimitCurve(DrawingContext *ctx)
if(ev_count == 0) if(ev_count == 0)
goto error_out; goto error_out;
ctx->limit_curve_count = 0;
for(int i = 0; i < ctx->n_group_elements; i++) { for(int i = 0; i < ctx->n_group_elements; i++) {
if(group[i].length % 2)
continue;
multiply_many(ws, fixedpoints, 3, ctx->cob, elements[i], coxeter_fixedpoints); multiply_many(ws, fixedpoints, 3, ctx->cob, elements[i], coxeter_fixedpoints);
x = ctx->limit_curve[3*i ] = gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column); x = ctx->limit_curve[3*ctx->limit_curve_count ] = gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column);
y = ctx->limit_curve[3*i+1] = gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column); y = ctx->limit_curve[3*ctx->limit_curve_count+1] = gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column);
ctx->limit_curve_count++;
if((x - ctx->marking.x)*(x - ctx->marking.x) + (y - ctx->marking.y)*(y - ctx->marking.y) < 25e-10) if((x - ctx->marking.x)*(x - ctx->marking.x) + (y - ctx->marking.y)*(y - ctx->marking.y) < 25e-10)
{ {
@ -95,19 +161,16 @@ int computeLimitCurve(DrawingContext *ctx)
fputc('a' + cur->letter, stdout); // bcbcbca, bacbcacab, bc bca cb fputc('a' + cur->letter, stdout); // bcbcbca, bacbcacab, bc bca cb
fputc('\n',stdout); fputc('\n',stdout);
} }
// bca abc acb = abc
} }
qsort(ctx->limit_curve, ctx->n_group_elements, 3*sizeof(double), compareAngle); qsort(ctx->limit_curve, ctx->limit_curve_count, 3*sizeof(double), compareAngle);
ctx->limit_curve_count = ctx->n_group_elements; // ctx->limit_curve_count = ctx->n_group_elements;
success = 1; success = 1;
error_out: error_out:
releaseTempMatrices(ctx->ws, 11+ctx->n_group_elements); releaseTempMatrices(ctx->ws, 14+ctx->n_group_elements);
return success; return success;
} }

View File

@ -13,7 +13,7 @@
#define ERROR(condition, msg, ...) if(condition){fprintf(stderr, msg, ##__VA_ARGS__); exit(1);} #define ERROR(condition, msg, ...) if(condition){fprintf(stderr, msg, ##__VA_ARGS__); exit(1);}
#define FCMP(x, y) gsl_fcmp(x, y, 1e-10) #define FCMP(x, y) gsl_fcmp(x, y, 1e-10)
#define MAX_TEMP_MATRICES 1200000 #define MAX_TEMP_MATRICES 600000
#define MAX_TEMP_VECTORS 100 #define MAX_TEMP_VECTORS 100
typedef struct _workspace { typedef struct _workspace {

742
main.c
View File

@ -11,458 +11,474 @@
#include "linalg.h" #include "linalg.h"
#define TOGGLE(a) do { (a) = !(a); } while(0) #define TOGGLE(a) do { (a) = !(a); } while(0)
#define SIGN(x) ((x) > 0 ? 1.0 : -1.0)
DrawingContext *screen_context; DrawingContext *screen_context;
// setup everything except cairo and dim, which will be provided by the graphics system // setup everything except cairo and dim, which will be provided by the graphics system
void setupContext(DrawingContext *ctx, int argc, char *argv[]) void setupContext(DrawingContext *ctx, int argc, char *argv[])
{ {
ctx->n_group_elements = NUM_GROUP_ELEMENTS; ctx->n_group_elements = NUM_GROUP_ELEMENTS;
ctx->p[0] = atoi(argv[1]); ctx->n_group_elements_combinatorial = NUM_GROUP_ELEMENTS_COMBINATORIAL;
ctx->p[1] = atoi(argv[2]); ctx->p[0] = atoi(argv[1]);
ctx->p[2] = atoi(argv[3]); ctx->p[1] = atoi(argv[2]);
ctx->k[0] = atoi(argv[4]); ctx->p[2] = atoi(argv[3]);
ctx->k[1] = atoi(argv[5]); ctx->k[0] = atoi(argv[4]);
ctx->k[2] = atoi(argv[6]); ctx->k[1] = atoi(argv[5]);
if(argc > 7) ctx->k[2] = atoi(argv[6]);
ctx->parameter = atof(argv[7]); if(argc > 7)
else ctx->parameter = atof(argv[7]);
ctx->parameter = 1.0; else
// ctx->parameter = 2.77; ctx->parameter = 1.0;
// ctx->parameter = 0.1; if(argc > 8)
ctx->show_boxes = 0; ctx->parameter2 = atof(argv[8]);
ctx->show_boxes2 = 0; else
ctx->show_attractors = 0; ctx->parameter2 = 1.0;
ctx->show_reflectors = 0; if(argc > 12) {
ctx->show_rotated_reflectors = 0; ctx->movie_filename = argv[9];
ctx->show_limit= 0; ctx->movie_parameter_duration = atof(argv[10]);
ctx->show_dual_limit= 0; ctx->movie_parameter2_duration = atof(argv[11]);
ctx->show_text = 1; ctx->movie_n_frames = atoi(argv[12]);
ctx->mode = 0; } else {
ctx->use_rotation_basis = 0; ctx->movie_n_frames = 0;
ctx->limit_with_lines = 1; }
ctx->use_repelling = 0; // ctx->parameter = 2.77;
ctx->show_marking = 1; // ctx->parameter = 0.1;
ctx->marking.x = -0.73679; ctx->show_boxes = 0;
ctx->marking.y = -0.01873; ctx->show_boxes2 = 0;
ctx->show_coxeter_orbit = 0; ctx->show_attractors = 0;
ctx->show_reflectors = 0;
ctx->show_rotated_reflectors = 0;
ctx->show_limit = 0;
ctx->show_dual_limit = 0;
ctx->show_text = 1;
ctx->mode = 0;
ctx->use_rotation_basis = 1;
ctx->limit_with_lines = 0;
ctx->use_repelling = 0;
ctx->show_marking = 0;
ctx->marking.x = -0.73679;
ctx->marking.y = -0.01873;
ctx->show_coxeter_orbit = 0;
ctx->limit_curve = malloc(3*ctx->n_group_elements*sizeof(double)); ctx->limit_curve = malloc(3*ctx->n_group_elements*sizeof(double));
ctx->limit_curve_count = -1; ctx->limit_curve_count = -1;
ctx->group = malloc(ctx->n_group_elements*sizeof(groupelement_t)); ctx->group = malloc(ctx->n_group_elements_combinatorial*sizeof(groupelement_t));
generate_triangle_group(ctx->group, ctx->n_group_elements, ctx->p[0], ctx->p[1], ctx->p[2]); generate_triangle_group(ctx->group, ctx->n_group_elements_combinatorial, ctx->p[0], ctx->p[1], ctx->p[2]);
// the temporary stuff // the temporary stuff
ctx->cartan = gsl_matrix_alloc(3, 3); ctx->cartan = gsl_matrix_alloc(3, 3);
ctx->cob = gsl_matrix_alloc(3, 3); ctx->cob = gsl_matrix_alloc(3, 3);
ctx->ws = workspace_alloc(3); ctx->ws = workspace_alloc(3);
} }
void destroyContext(DrawingContext *ctx) void destroyContext(DrawingContext *ctx)
{ {
free(ctx->limit_curve); free(ctx->limit_curve);
free(ctx->group); free(ctx->group);
gsl_matrix_free(ctx->cartan); gsl_matrix_free(ctx->cartan);
gsl_matrix_free(ctx->cob); gsl_matrix_free(ctx->cob);
workspace_free(ctx->ws); workspace_free(ctx->ws);
} }
void computeRotationMatrix(DrawingContext *ctx, gsl_matrix *result, const char *type) void computeMatrix(DrawingContext *ctx, gsl_matrix *result, const char *type)
{ {
gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix **gen = getTempMatrices(ctx->ws, 6);
gsl_matrix **gen = getTempMatrices(ctx->ws, 3);
// ERROR(strlen(type) != 2, "Invalid call of computeRotationMatrix()\n"); // ERROR(strlen(type) != 2, "Invalid call of computeRotationMatrix()\n");
initializeTriangleGenerators(gen, ctx->cartan); initializeTriangleGeneratorsCurrent(gen, ctx);
gsl_matrix_set_identity(tmp); gsl_matrix_set_identity(result);
for(int i = 0; i < strlen(type); i++) for(int i = 0; i < strlen(type); i++) {
multiply_right(tmp, gen[type[i]-'a'], ctx->ws); if(type[i] >= 'a' && type[i] <= 'c')
multiply_right(result, gen[type[i]-'a'], ctx->ws);
else if(type[i] >= 'A' && type[i] <= 'C')
multiply_right(result, gen[type[i]-'A'+3], ctx->ws);
}
rotation_frame(tmp, result, ctx->ws); releaseTempMatrices(ctx->ws, 6);
}
releaseTempMatrices(ctx->ws, 4); void computeRotationMatrixFrame(DrawingContext *ctx, gsl_matrix *result, const char *type)
{
gsl_matrix *tmp = getTempMatrix(ctx->ws);
computeMatrix(ctx, tmp, type);
rotation_frame(tmp, result, ctx->ws);
releaseTempMatrices(ctx->ws, 1);
} }
void computeBoxTransform(DrawingContext *ctx, char *word1, char *word2, gsl_matrix *result) void computeBoxTransform(DrawingContext *ctx, char *word1, char *word2, gsl_matrix *result)
{ {
vector_t p[2][3],i[2]; vector_t p[2][3],i[2];
vector_t std[4] = { vector_t std[4] = {
{-1, -1, 1}, {-1, -1, 1},
{-1, 1, 1}, {-1, 1, 1},
{1, 1, 1}, {1, 1, 1},
{1, -1, 1} {1, -1, 1}
}; };
gsl_vector **vertices = getTempVectors(ctx->ws, 4); gsl_vector **vertices = getTempVectors(ctx->ws, 4);
gsl_vector **std_vertices = getTempVectors(ctx->ws, 4); gsl_vector **std_vertices = getTempVectors(ctx->ws, 4);
gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix *tmp = getTempMatrix(ctx->ws);
gsl_matrix *to_frame = getTempMatrix(ctx->ws); gsl_matrix *to_frame = getTempMatrix(ctx->ws);
gsl_matrix *to_std_frame = getTempMatrix(ctx->ws); gsl_matrix *to_std_frame = getTempMatrix(ctx->ws);
fixedPoints(ctx, word1, p[0]); fixedPoints(ctx, word1, p[0]);
fixedPoints(ctx, word2, p[1]); fixedPoints(ctx, word2, p[1]);
// intersect attracting line with neutral line of the other element // intersect attracting line with neutral line of the other element
for(int j = 0; j < 2; j++) 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])); i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
// box consists of p[0][0], i[0], p[1][0], i[1] // box consists of p[0][0], i[0], p[1][0], i[1]
for(int i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
vectorToGsl(std[i], std_vertices[i]); vectorToGsl(std[i], std_vertices[i]);
vectorToGsl(p[0][0], vertices[0]); vectorToGsl(p[0][0], vertices[0]);
vectorToGsl(i[0], vertices[1]); vectorToGsl(i[0], vertices[1]);
vectorToGsl(p[1][0], vertices[2]); vectorToGsl(p[1][0], vertices[2]);
vectorToGsl(i[1], vertices[3]); vectorToGsl(i[1], vertices[3]);
projective_frame(std_vertices, to_std_frame, ctx->ws); projective_frame(std_vertices, to_std_frame, ctx->ws);
projective_frame(vertices, to_frame, ctx->ws); projective_frame(vertices, to_frame, ctx->ws);
invert(to_frame, tmp, ctx->ws); invert(to_frame, tmp, ctx->ws);
multiply(to_std_frame, tmp, result); multiply(to_std_frame, tmp, result);
/* /*
LOOP(i) { LOOP(i) {
LOOP(j) { LOOP(j) {
printf("%.4f ", gsl_matrix_get(result, i, j)); printf("%.4f ", gsl_matrix_get(result, i, j));
} }
printf("\n"); printf("\n");
}*/ }*/
releaseTempVectors(ctx->ws, 8); releaseTempVectors(ctx->ws, 8);
releaseTempMatrices(ctx->ws, 3); releaseTempMatrices(ctx->ws, 3);
} }
void updateMatrices(DrawingContext *ctx) void updateMatrices(DrawingContext *ctx)
{ {
double angle[3]; double angle[3];
LOOP(i) angle[i] = M_PI*ctx->k[i]/ctx->p[i]; LOOP(i) angle[i] = M_PI*ctx->k[i]/ctx->p[i];
cartanMatrix(ctx->cartan, angle[0], angle[1], angle[2], ctx->parameter); cartanMatrix(ctx->cartan, angle[0], angle[1], angle[2], ctx->parameter);
gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix *tmp = getTempMatrix(ctx->ws);
int nmodes = 5;
if(ctx->use_rotation_basis % 5 == 0) { if(ctx->use_rotation_basis % nmodes == 0) {
gsl_matrix_set(tmp, 0, 0, 0.0); gsl_matrix_set(tmp, 0, 0, 0.0);
gsl_matrix_set(tmp, 0, 1, sqrt(3.0)/2.0); gsl_matrix_set(tmp, 0, 1, sqrt(3.0)/2.0);
gsl_matrix_set(tmp, 0, 2, -sqrt(3.0)/2.0); gsl_matrix_set(tmp, 0, 2, -sqrt(3.0)/2.0);
gsl_matrix_set(tmp, 1, 0, 1.0); gsl_matrix_set(tmp, 1, 0, 1.0);
gsl_matrix_set(tmp, 1, 1, -0.5); gsl_matrix_set(tmp, 1, 1, -0.5);
gsl_matrix_set(tmp, 1, 2, -0.5); gsl_matrix_set(tmp, 1, 2, -0.5);
gsl_matrix_set(tmp, 2, 0, 1.0); gsl_matrix_set(tmp, 2, 0, 1.0);
gsl_matrix_set(tmp, 2, 1, 1.0); gsl_matrix_set(tmp, 2, 1, 1.0);
gsl_matrix_set(tmp, 2, 2, 1.0); gsl_matrix_set(tmp, 2, 2, 1.0);
gsl_matrix_memcpy(ctx->cob, tmp); gsl_matrix_memcpy(ctx->cob, tmp);
} else if(ctx->use_rotation_basis % 5 == 1) { } else if(ctx->use_rotation_basis % nmodes == 1) {
gsl_matrix_memcpy(ctx->cob, ctx->cartan); // is this a good choice of basis for any reason? gsl_matrix_set(tmp, 0, 0, 1.0);
} else if(ctx->use_rotation_basis % 5 == 2) { gsl_matrix_set(tmp, 0, 1, -1.0);
computeRotationMatrix(ctx, tmp, "ba"); gsl_matrix_set(tmp, 0, 2, 0.0);
invert(tmp, ctx->cob, ctx->ws); gsl_matrix_set(tmp, 1, 0, 1.0);
} else if(ctx->use_rotation_basis % 5 == 3) { gsl_matrix_set(tmp, 1, 1, 1.0);
computeBoxTransform(ctx, "bca", "abc", ctx->cob); gsl_matrix_set(tmp, 1, 2, 0.0);
// computeBoxTransform(ctx, "cab", "bca", ctx->cob); gsl_matrix_set(tmp, 2, 0, 0.0);
// computeBoxTransform(ctx, "acb", "cba", ctx->cob); gsl_matrix_set(tmp, 2, 1, 0.0);
} else { gsl_matrix_set(tmp, 2, 2, 1.0);
cartanMatrix(tmp, M_PI/ctx->p[0], M_PI/ctx->p[1], M_PI/ctx->p[2], 1.0); gsl_matrix_memcpy(ctx->cob, ctx->cartan); // is this a good choice of basis for any reason?
diagonalize_symmetric_form(tmp, ctx->cob, ctx->ws); multiply_left(tmp, ctx->cob, ctx->ws);
} } else if(ctx->use_rotation_basis % nmodes == 2) {
computeRotationMatrixFrame(ctx, tmp, "C");
invert(tmp, ctx->cob, ctx->ws);
} else if(ctx->use_rotation_basis % nmodes == 3) {
computeBoxTransform(ctx, "acb", "cba", ctx->cob);
// computeBoxTransform(ctx, "cab", "bca", ctx->cob);
// computeBoxTransform(ctx, "acb", "cba", ctx->cob);
} else {
cartanMatrix(tmp, M_PI/ctx->p[0], M_PI/ctx->p[1], M_PI/ctx->p[2], 1.0);
diagonalize_symmetric_form(tmp, ctx->cob, ctx->ws);
}
releaseTempMatrices(ctx->ws, 1); releaseTempMatrices(ctx->ws, 1);
} }
void output_info(DrawingContext *ctx) void output_info(DrawingContext *ctx)
{ {
vector_t p[4][3]; vector_t p[4][3];
point_t pt; point_t pt;
fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "abc", p[0]);
fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "bca", p[1]);
fixedPoints(ctx, "cab", p[2]); fixedPoints(ctx, "cab", p[2]);
pt = vectorToPoint(ctx, p[0][0]); pt = vectorToPoint(ctx, p[0][0]);
printf("(abc)-+ = (%f %f)\n", pt.x, pt.y); printf("(abc)-+ = (%f %f)\n", pt.x, pt.y);
pt = vectorToPoint(ctx, p[1][0]); pt = vectorToPoint(ctx, p[1][0]);
printf("(bca)-+ = (%f %f)\n", pt.x, pt.y); printf("(bca)-+ = (%f %f)\n", pt.x, pt.y);
} }
void print(DrawingContext *screen) void print(DrawingContext *screen)
{ {
DrawingContext file; DrawingContext file;
DimensionsInfo dim; DimensionsInfo dim;
cairo_surface_t *surface; cairo_surface_t *surface;
char filename[100]; char filename[100];
time_t t = time(NULL); time_t t = time(NULL);
strftime(filename, sizeof(filename), "screenshot_%Y%m%d_%H%M%S.pdf", localtime(&t)); strftime(filename, sizeof(filename), "screenshot_%Y%m%d_%H%M%S.pdf", localtime(&t));
memcpy(&file, screen, sizeof(file)); memcpy(&file, screen, sizeof(file));
dim.width = screen->dim->width; dim.width = screen->dim->width;
dim.height = screen->dim->width / sqrt(2.0); dim.height = screen->dim->width / sqrt(2.0);
dim.matrix = screen->dim->matrix; dim.matrix = screen->dim->matrix;
dim.matrix.y0 += ((double)dim.height - (double)screen->dim->height) / 2.0; // recenter vertically dim.matrix.y0 += ((double)dim.height - (double)screen->dim->height) / 2.0; // recenter vertically
updateDimensions(&dim); updateDimensions(&dim);
file.dim = &dim; file.dim = &dim;
surface = cairo_pdf_surface_create(filename, (double)dim.width, (double)dim.height); surface = cairo_pdf_surface_create(filename, (double)dim.width, (double)dim.height);
file.cairo = cairo_create(surface); file.cairo = cairo_create(surface);
draw(&file); draw(&file);
cairo_destroy(file.cairo); cairo_destroy(file.cairo);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
printf("Wrote sceenshot to file: %s\n", filename); printf("Wrote sceenshot to file: %s\n", filename);
} }
int processEvent(GraphicsInfo *info, XEvent *ev) int processEvent(GraphicsInfo *info, XEvent *ev)
{ {
int state; int state;
unsigned long key; unsigned long key;
char filename[100]; char filename[100];
// fprintf(stderr, "Event: %d\n", ev->type); // fprintf(stderr, "Event: %d\n", ev->type);
switch(ev->type) { switch(ev->type) {
case ButtonPress: case ButtonPress:
state = ev->xbutton.state & (ShiftMask | LockMask | ControlMask); state = ev->xbutton.state & (ShiftMask | LockMask | ControlMask);
if(ev->xbutton.button == 1 && state & ShiftMask) { if(ev->xbutton.button == 1 && state & ShiftMask) {
screen_context->marking.x = (double)ev->xbutton.x; screen_context->marking.x = (double)ev->xbutton.x;
screen_context->marking.y = (double)ev->xbutton.y; screen_context->marking.y = (double)ev->xbutton.y;
printf("mouse button pressed: %f, %f\n", screen_context->marking.x, screen_context->marking.y); printf("mouse button pressed: %f, %f\n", screen_context->marking.x, screen_context->marking.y);
cairo_set_matrix(screen_context->cairo, &screen_context->dim->matrix); cairo_set_matrix(screen_context->cairo, &screen_context->dim->matrix);
cairo_device_to_user(screen_context->cairo, &screen_context->marking.x, &screen_context->marking.y); cairo_device_to_user(screen_context->cairo, &screen_context->marking.x, &screen_context->marking.y);
printf("mouse button pressed transformed: %f, %f\n", screen_context->marking.x, screen_context->marking.y); printf("mouse button pressed transformed: %f, %f\n", screen_context->marking.x, screen_context->marking.y);
return STATUS_REDRAW; return STATUS_REDRAW;
} }
break; break;
case KeyPress: case KeyPress:
state = ev->xkey.state & (ShiftMask | LockMask | ControlMask); state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
key = XkbKeycodeToKeysym(ev->xkey.display, ev->xkey.keycode, 0, !!(state & ShiftMask)); key = XkbKeycodeToKeysym(ev->xkey.display, ev->xkey.keycode, 0, !!(state & ShiftMask));
printf("Key pressed: %ld\n", key); printf("Key pressed: %ld\n", key);
switch(key) { switch(key) {
case XK_Down: case XK_Down:
screen_context->parameter /= exp(0.002); if(ev->xkey.state & ShiftMask)
updateMatrices(screen_context); screen_context->parameter /= exp(0.00005);
computeLimitCurve(screen_context); else
break; screen_context->parameter /= exp(0.002);
case XK_Up: updateMatrices(screen_context);
screen_context->parameter *= exp(0.002); computeLimitCurve(screen_context);
updateMatrices(screen_context); break;
computeLimitCurve(screen_context); case XK_Up:
break; if(ev->xkey.state & ShiftMask)
case XK_Left: screen_context->parameter *= exp(0.00005);
screen_context->parameter /= exp(0.00002); else
updateMatrices(screen_context); screen_context->parameter *= exp(0.002);
computeLimitCurve(screen_context); updateMatrices(screen_context);
break; computeLimitCurve(screen_context);
case XK_Right: break;
screen_context->parameter *= exp(0.00002); case XK_Left:
updateMatrices(screen_context); if(ev->xkey.state & ShiftMask)
computeLimitCurve(screen_context); screen_context->parameter2 /= exp(0.00005);
break; else
case XK_Page_Down: screen_context->parameter2 /= exp(0.002);
screen_context->parameter /= exp(0.02); updateMatrices(screen_context);
updateMatrices(screen_context); computeLimitCurve(screen_context);
computeLimitCurve(screen_context); break;
break; case XK_Right:
case XK_Page_Up: if(ev->xkey.state & ShiftMask)
screen_context->parameter *= exp(0.02); screen_context->parameter2 *= exp(0.00005);
updateMatrices(screen_context); else
computeLimitCurve(screen_context); screen_context->parameter2 *= exp(0.002);
break; updateMatrices(screen_context);
case ' ': computeLimitCurve(screen_context);
screen_context->parameter = 5.57959706; break;
updateMatrices(screen_context); case XK_Page_Down:
computeLimitCurve(screen_context); screen_context->parameter /= exp(0.02);
break; updateMatrices(screen_context);
case XK_Return: computeLimitCurve(screen_context);
// screen_context->parameter = 2.76375163; break;
screen_context->parameter = 5.29063366; case XK_Page_Up:
updateMatrices(screen_context); screen_context->parameter *= exp(0.02);
computeLimitCurve(screen_context); updateMatrices(screen_context);
break; computeLimitCurve(screen_context);
case 'm': break;
printf("matrix.xx = %f;\n", info->dim->matrix.xx); case ' ':
printf("matrix.xy = %f;\n", info->dim->matrix.xy); screen_context->parameter = 5.57959706;
printf("matrix.x0 = %f;\n", info->dim->matrix.x0); updateMatrices(screen_context);
printf("matrix.yx = %f;\n", info->dim->matrix.yx); computeLimitCurve(screen_context);
printf("matrix.yy = %f;\n", info->dim->matrix.yy); break;
printf("matrix.y0 = %f;\n", info->dim->matrix.y0); case XK_Return:
break; // screen_context->parameter = 2.76375163;
case 'i': screen_context->parameter = 5.29063366;
output_info(screen_context); updateMatrices(screen_context);
break; computeLimitCurve(screen_context);
case 'b': break;
TOGGLE(screen_context->show_boxes); case 'm':
break; printf("matrix.xx = %f;\n", info->dim->matrix.xx);
case 'B': printf("matrix.xy = %f;\n", info->dim->matrix.xy);
TOGGLE(screen_context->show_boxes2); printf("matrix.x0 = %f;\n", info->dim->matrix.x0);
break; printf("matrix.yx = %f;\n", info->dim->matrix.yx);
case 'a': printf("matrix.yy = %f;\n", info->dim->matrix.yy);
TOGGLE(screen_context->show_attractors); printf("matrix.y0 = %f;\n", info->dim->matrix.y0);
break; break;
case 'r': case 'i':
TOGGLE(screen_context->show_reflectors); output_info(screen_context);
break; break;
case 'x': case 'b':
TOGGLE(screen_context->show_rotated_reflectors); TOGGLE(screen_context->show_boxes);
break; break;
case 'L': case 'B':
TOGGLE(screen_context->limit_with_lines); TOGGLE(screen_context->show_boxes2);
break; break;
case 'l': case 'a':
TOGGLE(screen_context->show_limit); TOGGLE(screen_context->show_attractors);
break; break;
case 'd': case 'r':
TOGGLE(screen_context->show_dual_limit); TOGGLE(screen_context->show_reflectors);
break; break;
case 'R': case 'x':
screen_context->use_rotation_basis++; TOGGLE(screen_context->show_rotated_reflectors);
updateMatrices(screen_context); break;
computeLimitCurve(screen_context); case 'L':
break; TOGGLE(screen_context->limit_with_lines);
case 'p': break;
print(screen_context); case 'l':
break; TOGGLE(screen_context->show_limit);
case 'M': break;
/* case 'd':
screen_context->limit_with_lines = 0; TOGGLE(screen_context->show_dual_limit);
double parameter_start = screen_context->parameter; break;
for(int i = 0; i <= 1300; i++) { case 'R':
if(i < 400) screen_context->use_rotation_basis++;
screen_context->parameter = exp(log(parameter_start)+0.002*i); updateMatrices(screen_context);
else if(i < 500) computeLimitCurve(screen_context);
screen_context->parameter = exp(log(parameter_start)+0.002*400); break;
else case 'p':
screen_context->parameter = exp(log(parameter_start)+0.002*(900-i)); print(screen_context);
updateMatrices(screen_context); break;
computeLimitCurve(screen_context); case 'M':
draw(screen_context); screen_context->limit_with_lines = 0;
sprintf(filename, "movie3/test%03d.png", i); double parameter_start = screen_context->parameter;
cairo_surface_write_to_png(info->buffer_surface, filename); double parameter2_start = screen_context->parameter2;
printf("Finished drawing %s\n", filename); for(int i = 0; i <= screen_context->movie_n_frames; i++) {
} screen_context->parameter = SIGN(parameter_start)*exp(log(fabs(parameter_start)) +
*/ i*screen_context->movie_parameter_duration/screen_context->movie_n_frames);
/* screen_context->parameter2 = SIGN(parameter2_start)*exp(log(fabs(parameter2_start)) +
screen_context->limit_with_lines = 0; i*screen_context->movie_parameter2_duration/screen_context->movie_n_frames);
double parameter_start = screen_context->parameter; updateMatrices(screen_context);
for(int i = 0; i <= 1300; i++) { computeLimitCurve(screen_context);
if(i < 400) draw(screen_context);
screen_context->parameter = exp(0.003*i); sprintf(filename, "output/%s%03d.png", screen_context->movie_filename, i);
else if(i < 500) cairo_surface_write_to_png(info->buffer_surface, filename);
screen_context->parameter = exp(0.003*400); printf("Finished drawing %s\n", filename);
else }
screen_context->parameter = exp(0.003*(900-i));
updateMatrices(screen_context);
computeLimitCurve(screen_context);
draw(screen_context);
sprintf(filename, "movie5/test%03d.png", i);
cairo_surface_write_to_png(info->buffer_surface, filename);
printf("Finished drawing %s\n", filename);
}
*/
screen_context->limit_with_lines = 0;
for(int i = 0; i <= 1000; i++) {
screen_context->parameter = exp(log(3.0)*((double)i/500-1));
updateMatrices(screen_context);
computeLimitCurve(screen_context);
draw(screen_context);
sprintf(filename, "output/movie8/test%04d.png", i);
// cairo_surface_write_to_png(info->buffer_surface, filename);
printf("Finished drawing %s\n", filename);
}
case 'f':
TOGGLE(screen_context->use_repelling);
computeLimitCurve(screen_context);
break;
case 't':
TOGGLE(screen_context->show_text);
break;
case 'c':
TOGGLE(screen_context->show_coxeter_orbit);
break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0':
screen_context->mode = key - '0';
break;
}
return STATUS_REDRAW; case 'f':
TOGGLE(screen_context->use_repelling);
computeLimitCurve(screen_context);
break;
case 't':
TOGGLE(screen_context->show_text);
break;
case 'c':
TOGGLE(screen_context->show_coxeter_orbit);
break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0':
screen_context->mode = key - '0';
break;
} }
return STATUS_NOTHING; return STATUS_REDRAW;
}
return STATUS_NOTHING;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
GraphicsInfo *info; GraphicsInfo *info;
screen_context = malloc(sizeof(DrawingContext)); screen_context = malloc(sizeof(DrawingContext));
setupContext(screen_context, argc, argv); setupContext(screen_context, argc, argv);
updateMatrices(screen_context); updateMatrices(screen_context);
computeLimitCurve(screen_context); computeLimitCurve(screen_context);
info = initCairo(0, KeyPressMask, 200, 200, "Triangle group"); info = initCairo(0, KeyPressMask, 200, 200, "Triangle group");
if(!info) if(!info)
return 1; return 1;
/* /*
info->dim->matrix.xx = 274.573171; info->dim->matrix.xx = 274.573171;
info->dim->matrix.xy = 0.000000; info->dim->matrix.xy = 0.000000;
info->dim->matrix.x0 = 583.073462; info->dim->matrix.x0 = 583.073462;
info->dim->matrix.yx = 0.000000; info->dim->matrix.yx = 0.000000;
info->dim->matrix.yy = 274.573171; info->dim->matrix.yy = 274.573171;
info->dim->matrix.y0 = 777.225293; info->dim->matrix.y0 = 777.225293;
*/ */
info->dim->matrix.xx = 274.573171; info->dim->matrix.xx = 274.573171;
info->dim->matrix.xy = 0.000000; info->dim->matrix.xy = 0.000000;
info->dim->matrix.x0 = 910.073462; info->dim->matrix.x0 = 910.073462;
info->dim->matrix.yx = 0.000000; info->dim->matrix.yx = 0.000000;
info->dim->matrix.yy = 274.573171; info->dim->matrix.yy = 274.573171;
info->dim->matrix.y0 = 509.225293; info->dim->matrix.y0 = 509.225293;
updateDimensions(info->dim); updateDimensions(info->dim);
screen_context->dim = info->dim; screen_context->dim = info->dim;
screen_context->cairo = info->buffer_context; screen_context->cairo = info->buffer_context;
startTimer(info); startTimer(info);
while(1) { while(1) {
int result = checkEvents(info, processEvent, NULL); int result = checkEvents(info, processEvent, NULL);
if(result == STATUS_QUIT) if(result == STATUS_QUIT)
return 0; return 0;
else if(result == STATUS_REDRAW) { else if(result == STATUS_REDRAW) {
struct timeval current_time; struct timeval current_time;
double start_time, intermediate_time, end_time; double start_time, intermediate_time, end_time;
gettimeofday(&current_time, 0); gettimeofday(&current_time, 0);
start_time = current_time.tv_sec + current_time.tv_usec*1e-6; start_time = current_time.tv_sec + current_time.tv_usec*1e-6;
draw(screen_context); draw(screen_context);
gettimeofday(&current_time, 0); gettimeofday(&current_time, 0);
intermediate_time = current_time.tv_sec + current_time.tv_usec*1e-6; 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_set_source_surface(info->front_context, info->buffer_surface, 0, 0);
cairo_paint(info->front_context); cairo_paint(info->front_context);
gettimeofday(&current_time, 0); gettimeofday(&current_time, 0);
end_time = current_time.tv_sec + current_time.tv_usec*1e-6; 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); 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);
} }
waitUpdateTimer(info);
}
free(screen_context); free(screen_context);
destroyCairo(info); destroyCairo(info);
destroyContext(screen_context); destroyContext(screen_context);
return 0; return 0;
} }

17
main.h
View File

@ -12,6 +12,11 @@
#define LOOP(i) for(int i = 0; i < 3; i++) #define LOOP(i) for(int i = 0; i < 3; i++)
#define NUM_GROUP_ELEMENTS 10000 #define NUM_GROUP_ELEMENTS 10000
#define NUM_GROUP_ELEMENTS_COMBINATORIAL 100000
// (0,1) -> 2, (1,2) -> 0, (2,0) -> 1
// (1,0) -> 5, (2,1) -> 3, (0,2) -> 4
#define ROTATION_LETTER(x,y) (((y)-(x)+3)%3 == 1 ? ((y)+1)%3 : ((x)+1)%3+3)
typedef struct { typedef struct {
double x[3]; double x[3];
@ -30,7 +35,13 @@ typedef struct {
// a priori parameter // a priori parameter
int p[3],k[3]; int p[3],k[3];
double parameter; double parameter;
double parameter2;
char *movie_filename;
double movie_parameter_duration;
double movie_parameter2_duration;
int movie_n_frames;
int n_group_elements; int n_group_elements;
int n_group_elements_combinatorial;
int show_boxes; int show_boxes;
int show_boxes2; int show_boxes2;
int show_attractors; int show_attractors;
@ -66,7 +77,8 @@ typedef enum {
// implemented in limit_set.c // implemented in limit_set.c
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s); void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s);
void initializeTriangleGenerators(gsl_matrix **gen, gsl_matrix *cartan); void initializeTriangleGenerators(gsl_matrix **gen, double a1, double a2, double a3, double s, double t, workspace_t *ws);
void initializeTriangleGeneratorsCurrent(gsl_matrix **gen, DrawingContext *ctx);
int computeLimitCurve(DrawingContext *ctx); int computeLimitCurve(DrawingContext *ctx);
// implemented in draw.c // implemented in draw.c
@ -96,7 +108,8 @@ void setupContext(DrawingContext *ctx, int argc, char *argv[]);
void destroyContext(DrawingContext *ctx); void destroyContext(DrawingContext *ctx);
void print(DrawingContext *screen); void print(DrawingContext *screen);
int processEvent(GraphicsInfo *info, XEvent *ev); int processEvent(GraphicsInfo *info, XEvent *ev);
void computeRotationMatrix(DrawingContext *ctx, gsl_matrix *result, const char *type); void computeMatrix(DrawingContext *ctx, gsl_matrix *result, const char *type);
void computeRotationMatrixFrame(DrawingContext *ctx, gsl_matrix *result, const char *type);
void updateMatrices(DrawingContext *ctx); void updateMatrices(DrawingContext *ctx);
static vector_t vectorFromGsl(gsl_vector *v) static vector_t vectorFromGsl(gsl_vector *v)

View File

@ -14,6 +14,7 @@ typedef struct _groupelement {
struct _groupelement *parent; struct _groupelement *parent;
struct _groupelement *inverse; struct _groupelement *inverse;
int letter; int letter;
int visited;
} groupelement_t; } groupelement_t;
int generate_triangle_group(groupelement_t *group, int size, int k1, int k2, int k3); int generate_triangle_group(groupelement_t *group, int size, int k1, int k2, int k3);