#include "main.h" #define FMOD(x,y) (fmod(x,y) < 0 ? fmod(x,y) + y : fmod(x,y)) #define ANGLE_DIFF(x,y) (FMOD((x)-(y), 2*M_PI)) #define ANGLE_IN_INTERVAL(a,b,x) (ANGLE_DIFF(x,a) < ANGLE_DIFF(b,a)) #define FLIP(x,y) do {double tmp = x; x = y; y = tmp;} while(0) // level 0: helper functions int isInsideBB(DrawingContext *ctx, point_t p) { cairo_user_to_device(ctx->cairo, &p.x, &p.y); return -p.x < ctx->dim->width && p.x < 3*ctx->dim->width && -p.y < ctx->dim->height && p.y < 3*ctx->dim->height; } 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(gsl_matrix *m, vector_t x) { vector_t out; LOOP(i) out.x[i] = 0.0; LOOP(i) LOOP(j) out.x[i] += gsl_matrix_get(m, i, j) * x.x[j]; return out; } vector_t apply_transpose(gsl_matrix *m, vector_t x) { vector_t out; LOOP(i) out.x[i] = 0.0; LOOP(i) LOOP(j) out.x[i] += gsl_matrix_get(m, j, i) * x.x[j]; return out; } int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out) { gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix *ev = getTempMatrix(ctx->ws); gsl_matrix **gen = getTempMatrices(ctx->ws, 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->ws, 5); return count; } // level 1: the elementary drawing functions, drawPoint, drawSegment2d void drawPoint(DrawingContext *ctx, point_t p) { cairo_t *C = ctx->cairo; cairo_save(C); cairo_arc(C, p.x, p.y, 5.0/ctx->dim->scalefactor, 0, 2*M_PI); cairo_close_path(C); cairo_fill(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) { 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 segments, 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); if(segments) drawSegment(ctx, prev, current); else drawCovector(ctx, cross(prev, current)); } if(segments) drawSegment(ctx, current, first); else drawCovector(ctx, cross(current, first)); va_end(args); } void drawTriangle(DrawingContext *ctx, const char *word) { vector_t p[3]; fixedPoints(ctx, word, p); drawPolygon(ctx, 1, 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, 1, 4, p[0][0], i[0], p[1][0], i[1]); } void drawBoxLines(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, 0, 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); } void drawRotationOrbit(DrawingContext *ctx, const char *word, vector_t start) { vector_t v[3], w; point_t p; double parameter, startangle; int iterations = 200; gsl_matrix *frame = getTempMatrix(ctx->ws); gsl_matrix *inverse = getTempMatrix(ctx->ws); gsl_vector *start_v = getTempVector(ctx->ws); gsl_vector *start_in_frame = getTempVector(ctx->ws); cairo_t *C = ctx->cairo; computeRotationMatrix(ctx, frame, word); 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]); solve(frame, start_v, start_in_frame, ctx->ws); parameter = gsl_vector_get(start_in_frame, 2); parameter /= sqrt(gsl_vector_get(start_in_frame, 0)*gsl_vector_get(start_in_frame, 0) + gsl_vector_get(start_in_frame, 1)*gsl_vector_get(start_in_frame, 1)); startangle = atan2(gsl_vector_get(start_in_frame, 1), gsl_vector_get(start_in_frame, 0)); int previous_inside = 0; for(int k = 0; k <= iterations; k++) { LOOP(i) w.x[i] = parameter * v[2].x[i] + cos(2*k*M_PI/iterations) * v[0].x[i] + sin(2*k*M_PI/iterations) * v[1].x[i]; p = vectorToPoint(ctx, w); if(isInsideBB(ctx, p)) { if(!previous_inside) cairo_move_to(C, p.x, p.y); else cairo_line_to(C, p.x, p.y); previous_inside = 1; } else { previous_inside = 0; } } cairo_stroke(C); releaseTempMatrices(ctx->ws, 2); releaseTempVectors(ctx->ws, 2); } void drawDualRotationOrbit(DrawingContext *ctx, const char *word, vector_t start) { vector_t v[3], w; point_t p; double parameter, startangle; int iterations = 200; gsl_matrix *frame = getTempMatrix(ctx->ws); gsl_matrix *inverse = getTempMatrix(ctx->ws); gsl_vector *start_v = getTempVector(ctx->ws); gsl_vector *start_in_frame = getTempVector(ctx->ws); cairo_t *C = ctx->cairo; computeRotationMatrix(ctx, frame, word); 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]); // solve(frame, start_v, start_in_frame, ctx->ws); gsl_blas_dgemv(CblasTrans, 1.0, frame, start_v, 0.0, start_in_frame); parameter = sqrt(gsl_vector_get(start_in_frame, 0)*gsl_vector_get(start_in_frame, 0) + gsl_vector_get(start_in_frame, 1)*gsl_vector_get(start_in_frame, 1)); parameter /= gsl_vector_get(start_in_frame, 2); startangle = atan2(gsl_vector_get(start_in_frame, 1), gsl_vector_get(start_in_frame, 0)); int previous_inside = 0; for(int k = 0; k <= iterations; k++) { LOOP(i) w.x[i] = parameter * v[2].x[i] + cos(2*k*M_PI/iterations) * v[0].x[i] + sin(2*k*M_PI/iterations) * v[1].x[i]; p = vectorToPoint(ctx, w); if(isInsideBB(ctx, p)) { if(!previous_inside) cairo_move_to(C, p.x, p.y); else cairo_line_to(C, p.x, p.y); previous_inside = 1; } else { previous_inside = 0; } } cairo_stroke(C); releaseTempMatrices(ctx->ws, 2); releaseTempVectors(ctx->ws, 2); } void drawArc(DrawingContext *ctx, const char *word, vector_t start, vector_type_t starttype, vector_t end, vector_type_t endtype, vector_t third, int contain) { vector_t v[3], w; point_t p; double radius, angle_start, angle_end, angle_third, angle, angle_end_delta, sign, angle_start_final, angle_end_final, angle_end_other; int iterations = 200; gsl_matrix *frame = getTempMatrix(ctx->ws); gsl_matrix *inverse = getTempMatrix(ctx->ws); gsl_vector *vector = getTempVector(ctx->ws); gsl_vector *vector_in_frame = getTempVector(ctx->ws); cairo_t *C = ctx->cairo; computeRotationMatrix(ctx, frame, word); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i); LOOP(i) gsl_vector_set(vector, i, start.x[i]); if(starttype == VT_POINT) { solve(frame, vector, vector_in_frame, ctx->ws); radius = sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) + gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1)); radius /= fabs(gsl_vector_get(vector_in_frame, 2)); angle_start = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2), gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2)); } else { gsl_blas_dgemv(CblasTrans, 1.0, frame, vector, 0.0, vector_in_frame); radius = fabs(gsl_vector_get(vector_in_frame, 2)); radius /= sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) + gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1)); angle_start = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2), gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2)); } LOOP(i) gsl_vector_set(vector, i, third.x[i]); solve(frame, vector, vector_in_frame, ctx->ws); angle_third = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2), gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2)); LOOP(i) gsl_vector_set(vector, i, end.x[i]); if(endtype == VT_POINT) { solve(frame, vector, vector_in_frame, ctx->ws); angle_end = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2), gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2)); } else { gsl_blas_dgemv(CblasTrans, 1.0, frame, vector, 0.0, vector_in_frame); // this is only the average angle angle_end = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2), gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2)); angle_end_delta = acos(-fabs(gsl_vector_get(vector_in_frame, 2))/radius/ sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) + gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1))); printf("angle_end_delta: %f\n", angle_end_delta); } int previous_inside = 0; for(int i = 0; i < 4; i++) { angle_start_final = angle_start; if(endtype == VT_POINT) { angle_end_final = angle_end; } else { if(i >= 2) { angle_end_final = angle_end - angle_end_delta; angle_end_other = angle_end + angle_end_delta; } else { angle_end_final = angle_end + angle_end_delta; angle_end_other = angle_end - angle_end_delta; } } if(i%2) FLIP(angle_start_final, angle_end_final); printf("start: %f, end: %f, other: %f, third: %f\n", angle_start_final, angle_end_final, angle_end_other, angle_third); printf("interval1: %d, interval2: %d, diff: %f %f %f\n", ANGLE_IN_INTERVAL(angle_start, angle_end_final, angle_end_other), ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_third), ANGLE_DIFF(angle_end_final, angle_start_final), ANGLE_DIFF(angle_end_other, angle_start_final), ANGLE_DIFF(angle_third, angle_start_final)); if(endtype == VT_LINE && ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_end_other)) continue; if(contain && !ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_third)) continue; if(!contain && ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_third)) continue; break; } // printf("angle_start: %f, angle_end: %f, angle_third: %f\n", angle_start, angle_end, angle_third); for(int k = 0; k <= iterations; k++) { angle = angle_start_final + (double)k/(double)iterations * ANGLE_DIFF(angle_end_final, angle_start_final); LOOP(i) w.x[i] = v[2].x[i] / radius + cos(angle) * v[0].x[i] + sin(angle) * v[1].x[i]; p = vectorToPoint(ctx, w); if(isInsideBB(ctx, p)) { if(!previous_inside) cairo_move_to(C, p.x, p.y); else cairo_line_to(C, p.x, p.y); previous_inside = 1; } else { previous_inside = 0; } } cairo_stroke(C); releaseTempMatrices(ctx->ws, 2); releaseTempVectors(ctx->ws, 2); } // 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) { int n = 3; vector_t p[6][3]; vector_t l[6][3]; fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "cab", p[2]); fixedPoints(ctx, "a cab a", p[3]); fixedPoints(ctx, "b abc b", p[4]); fixedPoints(ctx, "c bca c", p[5]); double color[6][3] = {{1,0,0},{0,0.7,0},{0,0,1},{0,1,1},{0,1,1},{0,1,1}}; for(int i = 0; i < n; i++) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]); for(int i = 0; i < n; i++) LOOP(j) { cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]); drawVector(ctx, p[i][j]); } for(int i = 0; i < n; i++) LOOP(j) { cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]); drawCovector(ctx, l[i][j]); } } void drawCurvedBox(DrawingContext *ctx) { vector_t p[6][3]; vector_t l[2][3]; fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "babcb", p[2]); fixedPoints(ctx, "ababcba", p[3]); fixedPoints(ctx, "bacac abc cacab", p[4]); fixedPoints(ctx, "abacac abc cacaba", p[5]); 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]); drawArc(ctx, "ab", p[0][0], VT_POINT, p[2][0], VT_POINT, p[1][0], 0); drawArc(ctx, "bcab", p[2][0], VT_POINT, l[1][0], VT_LINE, p[4][0], 1); drawArc(ctx, "ab", p[1][0], VT_POINT, p[3][0], VT_POINT, p[0][0], 0); drawArc(ctx, "abcaba", p[3][0], VT_POINT, l[0][0], VT_LINE, p[5][0], 1); drawCovector(ctx, l[0][0]); drawCovector(ctx, l[1][0]); } void drawBoxes(DrawingContext *ctx) { gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix **gen = getTempMatrices(ctx->ws, 3); cairo_t *C = ctx->cairo; vector_t p[6][3]; vector_t l[6][3]; vector_t alpha[6]; fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "bca", p[1]); fixedPoints(ctx, "cab", p[2]); initializeTriangleGenerators(gen, ctx->cartan); for(int i = 0; i < 6; i++) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]); LOOP(i) LOOP(j) alpha[i].x[j] = gsl_matrix_get(ctx->cartan, i, j); cairo_set_source_rgb(C, 0.5, 0.5, 0.5); drawCurvedBox(ctx); /* drawRotationOrbit(ctx, "ca", p[0][0]); drawRotationOrbit(ctx, "ab", p[1][0]); drawRotationOrbit(ctx, "bc", p[2][0]); drawRotationOrbit(ctx, "cbac", p[4][0]); drawRotationOrbit(ctx, "abca", p[5][0]); */ /* cairo_set_source_rgb(C, 0.0, 0.0, 1.0); drawDualRotationOrbit(ctx, "ca", l[0][2]); drawDualRotationOrbit(ctx, "ab", l[1][2]); drawDualRotationOrbit(ctx, "bc", l[2][2]); drawDualRotationOrbit(ctx, "bacb", l[3][2]); drawDualRotationOrbit(ctx, "cbac", l[4][2]); drawDualRotationOrbit(ctx, "abca", l[5][2]); */ /* cairo_set_source_rgb(C, 0, 0, 1); fixedPoints(ctx, "abc", p[0]); // fixedPoints(ctx, "ababcba", p[1]); drawRotationOrbit(ctx, "abcaba", p[0][0]); // abcaba a rar- r-ar a rar- a drawRotationOrbit(ctx, "ab", p[0][0]); // ab a rar- a rar- rar- a drawRotationOrbit(ctx, "abcabcba", p[0][0]); // abc abc ba drawCovector(ctx, cross(p[0][0],p[0][1])); drawCovector(ctx, cross(p[1][0],p[1][1])); cairo_set_source_rgb(C, 0, 0.7, 0); fixedPoints(ctx, "ab abc ba", p[0]); // fixedPoints(ctx, "ab ababcba ba", p[1]); drawRotationOrbit(ctx, "ababcababa", p[0][0]); // abcaba a rar- r-ar a rar- a drawRotationOrbit(ctx, "ab", p[0][0]); // ab a rar- a rar- rar- a drawRotationOrbit(ctx, "ababcabcbaba", p[0][0]); // abc abc ba drawCovector(ctx, cross(p[0][0],p[0][1])); drawCovector(ctx, cross(p[1][0],p[1][1])); */ cairo_set_source_rgb(C, 0, 0, 1.0); // drawRotationOrbit(ctx, "bcab", p[3][0]); // drawRotationOrbit(ctx, "abca", p[5][0]); // drawRotationOrbit(ctx, "bacb", p[3][0]); // LOOP(i) drawVector(ctx, p[i+3][0]); cairo_set_source_rgb(C, 0.5, 0.5, 0.5); // drawCovector(ctx, alpha[1]); // drawCovector(ctx, alpha[2]); /* alpha[3] = apply_transpose(gen[1], alpha[0]); drawCovector(ctx, alpha[3]); */ releaseTempMatrices(ctx->ws, 4); } void drawBoxes2(DrawingContext *ctx) { gsl_matrix *tmp = getTempMatrix(ctx->ws); gsl_matrix **gen = getTempMatrices(ctx->ws, 3); cairo_t *C = ctx->cairo; initializeTriangleGenerators(gen, ctx->cartan); // 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_source_rgb(C, 1, 0, 0); drawBox(ctx, "cab", "bca"); cairo_set_source_rgb(C, 1, 0.5, 0); drawBox(ctx, "bc bca cb", "bc abc cb"); drawBox(ctx, "bcbc bca cbcb", "bcbc abc cbcb"); drawBox(ctx, "bcbcbc bca cbcbcb", "bcbcbc abc cbcbcb"); drawBox(ctx, "bcbcbcbc bca cbcbcbcb", "bcbcbcbc abc cbcbcbcb"); drawBox(ctx, "bcbcbcbcbc bca cbcbcbcbcb", "bcbcbcbcbc abc cbcbcbcbcb"); */ cairo_set_source_rgb(C, 1, 0, 0); drawBox(ctx, "bca", "abc"); 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"); cairo_set_source_rgb(C, 1, 0, 0); drawBox(ctx, "ab ca cab ac ba", "ab ca bca ac ba"); drawBox(ctx, "ab caca cab acac ba", "ab caca bca acac ba"); drawBox(ctx, "ab cacaca cab acacac ba", "ab cacaca bca acacac ba"); drawBox(ctx, "ab cacacaca cab acacacac ba", "ab cacacaca bca acacacac ba"); drawBox(ctx, "ab cacacacaca cab acacacacac ba", "ab cacacacaca bca acacacacac ba"); /* 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"); */ // abc -> arar abc r-ar-a = (ar)³ // bca -> (ar)² (ra)³ (ar)-² -> a rarr a rar- r-ar rar- a = ababcba // a rar- r-ar a r-ar a rar- a r-ar ra-r a = abcacabacba // drawBox(ctx, "ab ca cab ac ba", "ab ca bca ac ba"); // drawBox(ctx, "ab ca bc bca cb ac ba", "ab ca bc abc cb ac ba"); // drawBox(ctx, "ab ca bc ab abc ba cb ac ba", "ab ca bc ab cab ba cb ac ba"); // these are the right boxes /* cairo_set_source_rgb(C, 1, 0.5, 0); drawBox(ctx, "abababab abc babababa", "abababab cab babababa"); drawBox(ctx, "ababab abc bababa", "ababab cab bababa"); drawBox(ctx, "abab abc baba", "abab cab baba"); drawBox(ctx, "ab abc ba", "ab cab ba"); 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, "ab a cab a ba", "ab a bca a ba"); // drawBox(ctx, "ab ca cab ac ba", "ab ca bca ac ba"); // drawBox(ctx, "cab", "bca"); // drawBox(ctx, "ca cab ac", "ca bca ac"); releaseTempMatrices(ctx->ws, 4); } void drawRotatedReflectors(DrawingContext *ctx) { gsl_matrix *rot = getTempMatrix(ctx->ws); gsl_matrix **gen = getTempMatrices(ctx->ws, 3); cairo_t *C = ctx->cairo; vector_t fp[3], fp2[3]; vector_t w; vector_t v[3]; cairo_set_source_rgb(C, 0.7, 0.7, 0.7); initializeTriangleGenerators(gen, ctx->cartan); LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j); multiply(gen[0], gen[1], rot); for(int j = 0; j < ctx->p[2]; j++) { drawCovector(ctx, v[0]); v[0] = apply_transpose(rot, v[0]); } LOOP(i) LOOP(j) { v[i].x[j] = (i==j) ? 1.0 : 0.0; } for(int j = 0; j < ctx->p[2]; j++) { drawVector(ctx, v[0]); v[0] = apply(rot, v[0]); } fixedPoints(ctx, "cab", fp); fixedPoints(ctx, "cacabac", fp2); drawRotationOrbit(ctx, "ac", fp[0]); releaseTempMatrices(ctx->ws, 4); } void drawDualLimitCurve(DrawingContext *ctx) { cairo_t *C = ctx->cairo; cairo_save(C); cairo_set_source_rgb(C, 0, 0, 0); int n = 18; vector_t p[18][3]; vector_t l[n][3]; /* fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "ab abc ba", p[1]); fixedPoints(ctx, "abab abc baba", p[2]); fixedPoints(ctx, "ababab abc bababa", p[3]); fixedPoints(ctx, "abababab abc babababa", p[4]); fixedPoints(ctx, "babababa abc abababab", p[5]); fixedPoints(ctx, "bababa abc ababab", p[6]); fixedPoints(ctx, "baba abc abab", p[7]); fixedPoints(ctx, "ba abc ab", p[8]); fixedPoints(ctx, "bca", p[9]); fixedPoints(ctx, "ab bca ba", p[10]); fixedPoints(ctx, "abab bca baba", p[11]); fixedPoints(ctx, "ababab bca bababa", p[12]); fixedPoints(ctx, "abababab bca babababa", p[13]); fixedPoints(ctx, "babababa bca abababab", p[14]); fixedPoints(ctx, "bababa bca ababab", p[15]); fixedPoints(ctx, "baba bca abab", p[16]); fixedPoints(ctx, "ba bca ab", p[17]); */ fixedPoints(ctx, "abc", p[0]); fixedPoints(ctx, "ac abc ca", p[1]); fixedPoints(ctx, "acac abc caca", p[2]); fixedPoints(ctx, "acacac abc cacaca", p[3]); fixedPoints(ctx, "acacacac abc cacacaca", p[4]); fixedPoints(ctx, "cacacaca abc acacacac", p[5]); fixedPoints(ctx, "cacaca abc acacac", p[6]); fixedPoints(ctx, "caca abc acac", p[7]); fixedPoints(ctx, "ca abc ac", p[8]); fixedPoints(ctx, "bca", p[9]); fixedPoints(ctx, "ac bca ca", p[10]); fixedPoints(ctx, "acac bca caca", p[11]); fixedPoints(ctx, "acacac bca cacaca", p[12]); fixedPoints(ctx, "acacacac bca cacacaca", p[13]); fixedPoints(ctx, "cacacaca bca acacacac", p[14]); fixedPoints(ctx, "cacaca bca acacac", p[15]); fixedPoints(ctx, "caca bca acac", p[16]); fixedPoints(ctx, "ca bca ac", p[17]); /* fixedPoints(ctx, "cab", p[2]); fixedPoints(ctx, "b abc b", p[3]); fixedPoints(ctx, "c bca c", p[4]); fixedPoints(ctx, "a cab a", p[5]); */ for(int i = 0; i < n; i++) { LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]); // drawCovector(ctx, l[i][0]); drawCovector(ctx, l[i][2]); } cairo_restore(C); } void drawLimitCurve(DrawingContext *ctx) { cairo_t *C = ctx->cairo; cairo_save(C); cairo_set_source_rgb(C, 0, 0, 0); if(ctx->limit_with_lines) { int previous_inside = 0; for(int i = 0; i < ctx->limit_curve_count; i++) { point_t p; p.x = ctx->limit_curve[3*i]; p.y = ctx->limit_curve[3*i+1]; if(isInsideBB(ctx, p)) { if(!previous_inside) cairo_move_to(C, p.x, p.y); else cairo_line_to(C, p.x, p.y); previous_inside = 1; } else { previous_inside = 0; } } cairo_stroke(C); } else { for(int i = 0; i < ctx->limit_curve_count; i++) { point_t p; p.x = ctx->limit_curve[3*i]; p.y = ctx->limit_curve[3*i+1]; if(isInsideBB(ctx, p)) { cairo_arc(C, p.x, p.y, 2.0/ctx->dim->scalefactor, 0, 2*M_PI); cairo_close_path(C); cairo_fill(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_count >= 0) { if(ctx->show_limit) drawLimitCurve(ctx); if(ctx->show_dual_limit) drawDualLimitCurve(ctx); if(ctx->show_attractors) drawAttractors(ctx); if(ctx->show_rotated_reflectors) drawRotatedReflectors(ctx); if(ctx->show_reflectors) drawReflectors(ctx); if(ctx->show_boxes) drawBoxes(ctx); if(ctx->show_boxes2) drawBoxes2(ctx); } cairo_identity_matrix(C); // text is in screen coordinates if(ctx->show_text) drawText(ctx); cairo_surface_flush(cairo_get_target(C)); }