#include #include #include #include #include #include #include "main.h" #include "initcairo.h" #include "triangle.h" #include "linalg.h" #define TOGGLE(a) do { (a) = !(a); } while(0) DrawingContext *screen_context; // setup everything except cairo and dim, which will be provided by the graphics system void setupContext(DrawingContext *ctx) { ctx->n_group_elements = NUM_GROUP_ELEMENTS; ctx->p[0] = 5; ctx->p[1] = 5; ctx->p[2] = 5; ctx->k[0] = 2; ctx->k[1] = 2; ctx->k[2] = 2; ctx->parameter = 3.0; ctx->show_boxes = 0; ctx->show_boxes2 = 0; ctx->show_attractors = 0; ctx->show_reflectors = 0; ctx->show_limit= 1; ctx->limit_with_lines = 1; ctx->use_repelling = 0; ctx->limit_curve = malloc(3*ctx->n_group_elements*sizeof(double)); ctx->limit_curve_valid = 0; ctx->group = malloc(ctx->n_group_elements*sizeof(groupelement_t)); generate_triangle_group(ctx->group, ctx->n_group_elements, ctx->p[0], ctx->p[1], ctx->p[2]); // the temporary stuff ctx->cartan = gsl_matrix_alloc(3, 3); ctx->cob = gsl_matrix_alloc(3, 3); ctx->ws = workspace_alloc(3); } void destroyContext(DrawingContext *ctx) { free(ctx->limit_curve); free(ctx->group); gsl_matrix_free(ctx->cartan); gsl_matrix_free(ctx->cob); workspace_free(ctx->ws); } void updateMatrices(DrawingContext *ctx) { double angle[3]; LOOP(i) angle[i] = M_PI*ctx->k[i]/ctx->p[i]; cartanMatrix(ctx->cartan, angle[0], angle[1], angle[2], ctx->parameter); gsl_matrix_memcpy(ctx->cob, ctx->cartan); // is this a good choice of basis } void print(DrawingContext *screen) { DrawingContext file; DimensionsInfo dim; cairo_surface_t *surface; char filename[100]; time_t t = time(NULL); strftime(filename, sizeof(filename), "screenshot_%Y%m%d_%H%M%S.pdf", localtime(&t)); memcpy(&file, screen, sizeof(file)); dim.width = screen->dim->width; dim.height = screen->dim->width / sqrt(2.0); dim.matrix = screen->dim->matrix; dim.matrix.y0 += ((double)dim.height - (double)screen->dim->height) / 2.0; // recenter vertically updateDimensions(&dim); file.dim = &dim; surface = cairo_pdf_surface_create(filename, (double)dim.width, (double)dim.height); file.cairo = cairo_create(surface); draw(&file); cairo_destroy(file.cairo); cairo_surface_destroy(surface); printf("Wrote sceenshot to file: %s\n", filename); } int processEvent(GraphicsInfo *info, XEvent *ev) { int state; unsigned long key; switch(ev->type) { case KeyPress: state = ev->xkey.state & (ShiftMask | LockMask | ControlMask); key = XkbKeycodeToKeysym(ev->xkey.display, ev->xkey.keycode, 0, !!(state & ShiftMask)); printf("Key pressed: %ld\n", key); switch(key) { case XK_Down: screen_context->parameter /= exp(0.002); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Up: screen_context->parameter *= exp(0.002); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Left: screen_context->parameter /= exp(0.0001); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Right: screen_context->parameter *= exp(0.0001); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Page_Down: screen_context->parameter /= exp(0.2); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Page_Up: screen_context->parameter *= exp(0.2); updateMatrices(screen_context); computeLimitCurve(screen_context); break; case ' ': screen_context->parameter = 2.890053638; updateMatrices(screen_context); computeLimitCurve(screen_context); break; case XK_Return: screen_context->parameter = 2.76375163; updateMatrices(screen_context); computeLimitCurve(screen_context); break; case 'm': printf("matrix.xx = %f;\n", info->dim->matrix.xx); printf("matrix.xy = %f;\n", info->dim->matrix.xy); printf("matrix.x0 = %f;\n", info->dim->matrix.x0); printf("matrix.yx = %f;\n", info->dim->matrix.yx); printf("matrix.yy = %f;\n", info->dim->matrix.yy); printf("matrix.y0 = %f;\n", info->dim->matrix.y0); break; case 'b': TOGGLE(screen_context->show_boxes); break; case 'B': TOGGLE(screen_context->show_boxes2); break; case 'a': TOGGLE(screen_context->show_attractors); break; case 'r': TOGGLE(screen_context->show_reflectors); break; case 'L': TOGGLE(screen_context->limit_with_lines); break; case 'l': TOGGLE(screen_context->show_limit); break; case 'p': print(screen_context); break; case 'f': TOGGLE(screen_context->use_repelling); computeLimitCurve(screen_context); } return STATUS_REDRAW; } return STATUS_NOTHING; } int main() { GraphicsInfo *info; screen_context = malloc(sizeof(DrawingContext)); setupContext(screen_context); updateMatrices(screen_context); computeLimitCurve(screen_context); info = initCairo(0, KeyPressMask, 200, 200, "Triangle group"); if(!info) return 1; info->dim->matrix.xx = 837.930824; info->dim->matrix.xy = -712.651341; info->dim->matrix.x0 = 180.427716; info->dim->matrix.yx = 712.651341; info->dim->matrix.yy = 837.930824; info->dim->matrix.y0 = 1412.553240; updateDimensions(info->dim); screen_context->dim = info->dim; screen_context->cairo = info->buffer_context; startTimer(info); while(1) { int result = checkEvents(info, processEvent, NULL); if(result == STATUS_QUIT) return 0; else if(result == STATUS_REDRAW) { struct timeval current_time; double start_time, intermediate_time, end_time; gettimeofday(¤t_time, 0); start_time = current_time.tv_sec + current_time.tv_usec*1e-6; draw(screen_context); gettimeofday(¤t_time, 0); intermediate_time = current_time.tv_sec + current_time.tv_usec*1e-6; cairo_set_source_surface(info->front_context, info->buffer_surface, 0, 0); cairo_paint(info->front_context); gettimeofday(¤t_time, 0); end_time = current_time.tv_sec + current_time.tv_usec*1e-6; printf("drawing finished in %.2f milliseconds, of which %.2f milliseconds were buffer switching\n", (end_time - start_time) * 1000, (end_time - intermediate_time) * 1000); } waitUpdateTimer(info); } free(screen_context); destroyCairo(info); destroyContext(screen_context); return 0; }