triangle group code reorganization
This commit is contained in:
407
draw.c
Normal file
407
draw.c
Normal file
@@ -0,0 +1,407 @@
|
||||
#include "main.h"
|
||||
|
||||
// level 0: helper functions
|
||||
|
||||
vector_t cross(vector_t a, vector_t b)
|
||||
{
|
||||
vector_t result;
|
||||
result.x[0] = a.x[1]*b.x[2] - a.x[2]*b.x[1];
|
||||
result.x[1] = a.x[2]*b.x[0] - a.x[0]*b.x[2];
|
||||
result.x[2] = a.x[0]*b.x[1] - a.x[1]*b.x[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
vector_t apply(DrawingContext *ctx, gsl_matrix *m, vector_t x)
|
||||
{
|
||||
gsl_vector *tmp = getTempVector(ctx);
|
||||
gsl_vector *tmp2 = getTempVector(ctx);
|
||||
vector_t out;
|
||||
|
||||
LOOP(i) gsl_vector_set(tmp, i, x.x[i]);
|
||||
gsl_blas_dgemv(CblasNoTrans, 1.0, m, tmp, 0.0, tmp2);
|
||||
LOOP(i) out.x[i] = gsl_vector_get(tmp2, i);
|
||||
|
||||
releaseTempVectors(ctx, 2);
|
||||
}
|
||||
|
||||
int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out)
|
||||
{
|
||||
gsl_matrix *tmp = getTempMatrix(ctx);
|
||||
gsl_matrix *ev = getTempMatrix(ctx);
|
||||
gsl_matrix **gen = getTempMatrices(ctx, 3);
|
||||
|
||||
initializeTriangleGenerators(gen, ctx->cartan);
|
||||
|
||||
gsl_matrix_set_identity(tmp);
|
||||
for(int i = 0; i < strlen(word); i++) {
|
||||
if(word[i] == ' ')
|
||||
continue;
|
||||
multiply_right(tmp, gen[word[i]-'a'], ctx->ws);
|
||||
}
|
||||
int count = real_eigenvectors(tmp, ev, ctx->ws);
|
||||
|
||||
LOOP(i) LOOP(j) out[i].x[j] = gsl_matrix_get(ev, j, i);
|
||||
|
||||
releaseTempMatrices(ctx, 5);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void transformFrameStd(DrawingContext *ctx, vector_t *x, gsl_matrix *out)
|
||||
{
|
||||
gsl_matrix *tmp = getTempMatrix(ctx);
|
||||
gsl_vector *fourth = getTempVector(ctx);
|
||||
gsl_vector *lambda = getTempVector(ctx);
|
||||
int s;
|
||||
|
||||
LOOP(i) LOOP(j) gsl_matrix_set(out, j, i, x[i].x[j]);
|
||||
gsl_matrix_memcpy(tmp, out);
|
||||
gsl_linalg_LU_decomp(tmp, ctx->ws->permutation, &s);
|
||||
gsl_linalg_LU_solve(tmp, ctx->ws->permutation, fourth, lambda);
|
||||
|
||||
LOOP(i) LOOP(j) *gsl_matrix_ptr(out, i, j) *= gsl_vector_get(lambda, j);
|
||||
|
||||
gsl_matrix_fprintf(stdout, out, "%f");
|
||||
|
||||
releaseTempMatrices(ctx, 1);
|
||||
releaseTempVectors(ctx, 2);
|
||||
}
|
||||
|
||||
// level 1: the elementary drawing functions, drawPoint, drawSegment2d
|
||||
|
||||
void drawPoint(DrawingContext *ctx, point_t p)
|
||||
{
|
||||
cairo_t *C = ctx->cairo;
|
||||
|
||||
cairo_save(C);
|
||||
cairo_move_to(C, p.x, p.y);
|
||||
cairo_close_path(C);
|
||||
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_width(C, 10.0/ctx->dim->scalefactor);
|
||||
cairo_stroke(C);
|
||||
cairo_restore(C);
|
||||
}
|
||||
|
||||
void drawSegment2d(DrawingContext *ctx, point_t a, point_t b)
|
||||
{
|
||||
cairo_t *C = ctx->cairo;
|
||||
cairo_move_to(C, a.x, a.y);
|
||||
cairo_line_to(C, b.x, b.y);
|
||||
cairo_stroke(C);
|
||||
}
|
||||
|
||||
// level 2: drawVector, drawCovector, drawSegment
|
||||
|
||||
static point_t vectorToPoint(DrawingContext *ctx, vector_t in)
|
||||
{
|
||||
double x[3];
|
||||
point_t out;
|
||||
|
||||
LOOP(i) x[i] = 0.0;
|
||||
LOOP(i) LOOP(j) x[i] += gsl_matrix_get(ctx->cob, i, j) * in.x[j];
|
||||
|
||||
out.x = x[0] / x[2];
|
||||
out.y = x[1] / x[2];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void drawVector(DrawingContext *ctx, vector_t v)
|
||||
{
|
||||
drawPoint(ctx, vectorToPoint(ctx, v));
|
||||
}
|
||||
|
||||
static void drawImplicitLine(DrawingContext *ctx, double a, double b, double c)
|
||||
{
|
||||
double norm, lambda;
|
||||
point_t m, s, xminus, xplus;
|
||||
m.x = ctx->dim->center_x;
|
||||
m.y = ctx->dim->center_y;
|
||||
lambda = (a*m.x + b*m.y + c)/(a*a + b*b);
|
||||
s.x = m.x - lambda*a;
|
||||
s.y = m.y - lambda*b;
|
||||
norm = sqrt(a*a + b*b);
|
||||
xminus.x = s.x - ctx->dim->radius * b / norm;
|
||||
xminus.y = s.y + ctx->dim->radius * a / norm;
|
||||
xplus.x = s.x + ctx->dim->radius * b / norm;
|
||||
xplus.y = s.y - ctx->dim->radius * a / norm;
|
||||
|
||||
drawSegment2d(ctx, xminus, xplus);
|
||||
}
|
||||
|
||||
void drawCovector(DrawingContext *ctx, vector_t v)
|
||||
{
|
||||
double x[3];
|
||||
double cofactor;
|
||||
|
||||
LOOP(i) x[i] = 0.0;
|
||||
LOOP(i) LOOP(j) {
|
||||
cofactor = gsl_matrix_get(ctx->cob, (i+1)%3, (j+1)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+2)%3)
|
||||
- gsl_matrix_get(ctx->cob, (i+1)%3, (j+2)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+1)%3);
|
||||
x[i] += cofactor * v.x[j];
|
||||
}
|
||||
|
||||
drawImplicitLine(ctx, x[0], x[1], x[2]);
|
||||
}
|
||||
|
||||
void drawSegment(DrawingContext *ctx, vector_t a, vector_t b)
|
||||
{
|
||||
drawSegment2d(ctx, vectorToPoint(ctx, a), vectorToPoint(ctx, b));
|
||||
}
|
||||
|
||||
// level 3: boxes and polygons
|
||||
|
||||
void drawPolygon(DrawingContext *ctx, int sides, ...)
|
||||
{
|
||||
va_list args;
|
||||
vector_t first, prev, current;
|
||||
|
||||
va_start(args, sides);
|
||||
|
||||
first = va_arg(args, vector_t);
|
||||
current = first;
|
||||
for(int i = 0; i < sides-1; i++) {
|
||||
prev = current;
|
||||
current = va_arg(args, vector_t);
|
||||
drawSegment(ctx, prev, current);
|
||||
}
|
||||
drawSegment(ctx, current, first);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void drawTriangle(DrawingContext *ctx, const char *word)
|
||||
{
|
||||
vector_t p[3];
|
||||
|
||||
fixedPoints(ctx, word, p);
|
||||
drawPolygon(ctx, 3, p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
void drawBox(DrawingContext *ctx, const char *word1, const char *word2)
|
||||
{
|
||||
vector_t p[2][3],i[2];
|
||||
|
||||
fixedPoints(ctx, word1, p[0]);
|
||||
fixedPoints(ctx, word2, p[1]);
|
||||
|
||||
// intersect attracting line with neutral line of the other element
|
||||
for(int j = 0; j < 2; j++)
|
||||
i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
|
||||
|
||||
drawPolygon(ctx, 4, p[0][0], i[0], p[1][0], i[1]);
|
||||
}
|
||||
|
||||
void drawBoxStd(DrawingContext *ctx, const char *word, char base)
|
||||
{
|
||||
char word1[100];
|
||||
char word2[100];
|
||||
|
||||
int len = strlen(word);
|
||||
if(len*2 + 4 > 100)
|
||||
return;
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
word1[i] = word1[2*len+2-i] = word[i];
|
||||
word2[i] = word2[2*len+2-i] = word[i];
|
||||
}
|
||||
word1[2*len+3] = 0;
|
||||
word2[2*len+3] = 0;
|
||||
|
||||
LOOP(i) word1[len+i] = (base-'A'+6+i+1)%3+'a';
|
||||
LOOP(i) word2[len+i] = (base-'A'+6-i-1)%3+'a';
|
||||
|
||||
// printf("Words: %s %s\n", word1, word2);
|
||||
|
||||
drawBox(ctx, word1, word2);
|
||||
}
|
||||
|
||||
// level 4: draw the actual image components
|
||||
|
||||
void drawReflectors(DrawingContext *ctx)
|
||||
{
|
||||
vector_t v[3];
|
||||
|
||||
cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
|
||||
|
||||
LOOP(i) LOOP(j) { v[i].x[j] = (i==j) ? 1.0 : 0.0; }
|
||||
LOOP(i) drawVector(ctx, v[i]);
|
||||
|
||||
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
|
||||
LOOP(i) drawCovector(ctx, v[i]);
|
||||
}
|
||||
|
||||
void drawAttractors(DrawingContext *ctx)
|
||||
{
|
||||
vector_t p[3][3];
|
||||
vector_t l[3][3];
|
||||
|
||||
fixedPoints(ctx, "abc", p[0]);
|
||||
fixedPoints(ctx, "bca", p[1]);
|
||||
fixedPoints(ctx, "cab", p[2]);
|
||||
|
||||
double color[3][3] = {{1,0,0},{0,0.7,0},{0,0,1}};
|
||||
|
||||
LOOP(i) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]);
|
||||
|
||||
LOOP(i) LOOP(j) {
|
||||
cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
|
||||
drawVector(ctx, p[i][j]);
|
||||
}
|
||||
|
||||
LOOP(i) LOOP(j) {
|
||||
cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
|
||||
drawCovector(ctx, l[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
void drawBoxes(DrawingContext *ctx)
|
||||
{
|
||||
cairo_t *C = ctx->cairo;
|
||||
|
||||
/*
|
||||
cairo_set_source_rgb(C, 1, 0, 0);
|
||||
drawTriangle(ctx, "abc");
|
||||
cairo_set_source_rgb(C, 0, 0, 1);
|
||||
drawTriangle(ctx, "aca abc aca");
|
||||
drawTriangle(ctx, "acac abc caca");
|
||||
drawTriangle(ctx, "acaca abc acaca");
|
||||
cairo_set_source_rgb(C, 0, 0.8, 0);
|
||||
drawTriangle(ctx, "cac abc cac");
|
||||
drawTriangle(ctx, "caca abc acac");
|
||||
drawTriangle(ctx, "cacac abc cacac");
|
||||
*/
|
||||
|
||||
cairo_set_source_rgb(C, 1, 0, 0);
|
||||
drawBoxStd(ctx, "c", 'C');
|
||||
drawBoxStd(ctx, "", 'B');
|
||||
drawBoxStd(ctx, "a", 'A');
|
||||
drawBoxStd(ctx, "", 'C');
|
||||
drawBoxStd(ctx, "b", 'B');
|
||||
|
||||
cairo_set_source_rgb(C, 0, 0, 0);
|
||||
drawBoxStd(ctx, "ca", 'A');
|
||||
drawBoxStd(ctx, "cac", 'C');
|
||||
drawBoxStd(ctx, "caca", 'A');
|
||||
drawBoxStd(ctx, "acac", 'C');
|
||||
drawBoxStd(ctx, "aca", 'A');
|
||||
drawBoxStd(ctx, "ac", 'C');
|
||||
|
||||
drawBoxStd(ctx, "aca cb", 'B');
|
||||
drawBoxStd(ctx, "aca cbc", 'C');
|
||||
drawBoxStd(ctx, "aca cbcb", 'B');
|
||||
drawBoxStd(ctx, "aca bcbc", 'C');
|
||||
drawBoxStd(ctx, "aca bcb", 'B');
|
||||
drawBoxStd(ctx, "aca bc", 'C');
|
||||
|
||||
drawBoxStd(ctx, "caca cb", 'B');
|
||||
drawBoxStd(ctx, "caca cbc", 'C');
|
||||
drawBoxStd(ctx, "caca cbcb", 'B');
|
||||
drawBoxStd(ctx, "caca bcbc", 'C');
|
||||
drawBoxStd(ctx, "caca bcb", 'B');
|
||||
drawBoxStd(ctx, "caca bc", 'C');
|
||||
|
||||
cairo_set_source_rgb(C, 1, 0, 1);
|
||||
drawBoxStd(ctx, "ca bc", 'C');
|
||||
drawBoxStd(ctx, "ca bcb", 'B');
|
||||
drawBoxStd(ctx, "ca bcbc", 'C');
|
||||
drawBoxStd(ctx, "ca cbcb", 'B');
|
||||
drawBoxStd(ctx, "ca cbc", 'C');
|
||||
drawBoxStd(ctx, "ca cb", 'B');
|
||||
|
||||
cairo_set_source_rgb(C, 0, 1, 0);
|
||||
// drawBoxStd(ctx, "ca bc", 'C');
|
||||
drawBoxStd(ctx, "cabc ba", 'A');
|
||||
drawBoxStd(ctx, "cabc bab", 'B');
|
||||
drawBoxStd(ctx, "cabc baba", 'A');
|
||||
drawBoxStd(ctx, "cabc abab", 'B');
|
||||
drawBoxStd(ctx, "cabc aba", 'A');
|
||||
drawBoxStd(ctx, "cabc ab", 'B');
|
||||
}
|
||||
|
||||
void drawLimitCurve(DrawingContext *ctx)
|
||||
{
|
||||
cairo_t *C = ctx->cairo;
|
||||
|
||||
cairo_save(C);
|
||||
|
||||
int previous_inside = 0;
|
||||
for(int i = 0; i < ctx->n_group_elements; i++) {
|
||||
double x = ctx->limit_curve[3*i];
|
||||
double y = ctx->limit_curve[3*i+1];
|
||||
|
||||
cairo_user_to_device(C, &x, &y);
|
||||
|
||||
if(-x < ctx->dim->width && x < 3*ctx->dim->width && -y < ctx->dim->height && y < 3*ctx->dim->height) {
|
||||
if(ctx->limit_with_lines) {
|
||||
if(!previous_inside)
|
||||
cairo_move_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
|
||||
else
|
||||
cairo_line_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
|
||||
} else {
|
||||
cairo_move_to(C, ctx->limit_curve[3*i], ctx->limit_curve[3*i+1]);
|
||||
cairo_close_path(C);
|
||||
}
|
||||
previous_inside = 1;
|
||||
} else {
|
||||
previous_inside = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!ctx->limit_with_lines) { // draw dots instead of lines
|
||||
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_width(C, 3.0/ctx->dim->scalefactor);
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(C, 0, 0, 0);
|
||||
cairo_stroke(C);
|
||||
|
||||
cairo_restore(C);
|
||||
}
|
||||
|
||||
void drawText(DrawingContext *ctx)
|
||||
{
|
||||
cairo_move_to(ctx->cairo, 15, 30);
|
||||
cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
|
||||
char buf[100];
|
||||
sprintf(buf, "t = exp(%.8f) = %.8f", log(ctx->parameter), ctx->parameter);
|
||||
cairo_show_text(ctx->cairo, buf);
|
||||
}
|
||||
|
||||
// level 5: put everything together
|
||||
|
||||
void draw(DrawingContext *ctx)
|
||||
{
|
||||
cairo_t *C = ctx->cairo;
|
||||
|
||||
cairo_set_source_rgb(C, 1, 1, 1);
|
||||
cairo_paint(C);
|
||||
|
||||
cairo_set_matrix(C, &ctx->dim->matrix);
|
||||
|
||||
// defaults; use save/restore whenever these are changed
|
||||
cairo_set_line_width(C, 1.0/ctx->dim->scalefactor);
|
||||
cairo_set_font_size(C, 16);
|
||||
cairo_set_line_join(C, CAIRO_LINE_JOIN_BEVEL);
|
||||
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||
|
||||
if(ctx->limit_curve_valid) {
|
||||
if(ctx->show_limit)
|
||||
drawLimitCurve(ctx);
|
||||
|
||||
if(ctx->show_boxes)
|
||||
drawBoxes(ctx);
|
||||
|
||||
if(ctx->show_attractors)
|
||||
drawAttractors(ctx);
|
||||
|
||||
if(ctx->show_reflectors)
|
||||
drawReflectors(ctx);
|
||||
}
|
||||
|
||||
cairo_identity_matrix(C); // text is in screen coordinates
|
||||
|
||||
drawText(ctx);
|
||||
|
||||
cairo_surface_flush(cairo_get_target(C));
|
||||
}
|
||||
Reference in New Issue
Block a user